我阅读了关于 GCD 队列的 Apple 文档,并开始想知道如果我可以说修改一个在串行队列中不是线程安全的 NSMutableArray 类型的实例成员会发生什么?串行队列将保证我串行执行操作,但我仍然觉得我需要做一个 @syncrhonized 块或其他技术来强制内存屏障,因为据我所知,我的串行队列上的任务可以被调用在不同的线程上。那是对的吗?这是一个简单的例子:

@interface Foo : NSObject

-(void)addNumber:(NSNumber*)number;
-(void)printNumbers;
-(void)clearNumbers;

@end

@implementation Foo
{
   dispatch_queue_t _queue;
   NSMutableArray<NSNumber*>* _numbers;
}

-(instancetype)init
{
   if (self = [super init])
   {
       _queue = dispatch_queue_create(NULL, NULL);
       _numbers = [NSMutableArray array];
   }
   return self;
}

-(void)addNumber:(NSNumber*)number
{
   dispatch_async(_queue,
   ^{
       [_numbers addObject:number];
   });
}

-(void)printNumbers
{
   dispatch_async(_queue,
   ^{
       for (NSNumber* number in _numbers)
       {
           NSLog(@“%@“, number);
       }
   });
}

-(void)clearNumbers
{
   dispatch_async(_queue,
   ^{
       _numbers = [NSMutableArray array];
   });
}
@end;

据我所知,如果我从任意线程调用成员方法,我可能会在这里遇到内存问题?或者 GCD 在幕后提供了一些保证,为什么我不需要强制内存屏障?查看示例,我没有在任何地方找到这样的构造,但是来自 C++,在锁定下触摸成员变量是有意义的。

最佳答案

如果你的队列是一个串行队列,它一次只允许一个操作,不管它在哪个线程上运行。因此,如果对资源的每次访问都发生在队列上,则无需使用锁或信号量进一步保护该资源。事实上,可以使用调度队列作为锁定机制,并且对于某些应用程序,它可以很好地工作。

现在,如果您的队列是并发队列,那就是另一回事了,因为多个操作可以在并发队列上同时运行。但是,GCD 提供了 dispatch_barrier_syncdispatch_barrier_async API。通过这两个函数调用启动的操作将导致队列在执行块之前等待所有其他操作完成,然后在块完成之前禁止任何更多操作运行。通过这种方式,它可以暂时使队列表现得像一个串行队列,甚至允许将并发队列用作一种锁定机制(例如,允许通过正常的 dispatch_sync 调用读取资源,但通过dispatch_barrier_async 。如果读取非常频繁而写入非常不频繁,这可以很好地执行)。

关于objective-c - GCD - 串行队列是否需要 `NSLock` 或内存屏障来同步工作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48628952/

10-12 00:15
查看更多