Objective c 我可以安全地使用';非原子';自定义并发队列的调度屏障内的IVAR?

Objective c 我可以安全地使用';非原子';自定义并发队列的调度屏障内的IVAR?,objective-c,multithreading,swift,concurrency,grand-central-dispatch,Objective C,Multithreading,Swift,Concurrency,Grand Central Dispatch,从自定义并发队列的调度屏障内访问非原子IVAR安全吗? 以下代码段是使用分派屏障的方法的简化版本: - (void)cacheData:(NSData *)data toFile:(NSString *)fileName { dispatch_barrier_async(concurrentQueue, ^{ [_memoryCache setObject:data forKey:fileName]; // ... } }); }

从自定义并发队列的调度屏障内访问非原子IVAR安全吗? 以下代码段是使用分派屏障的方法的简化版本:

- (void)cacheData:(NSData *)data toFile:(NSString *)fileName {
    dispatch_barrier_async(concurrentQueue, ^{
        [_memoryCache setObject:data forKey:fileName];
        // ...
        }
    });
}

我想对非原子线程安全性有一个基本的了解(即,不需要使用原子与非原子ivar的开销)。 这与Swift和Objective-C一样重要。

≠ 线程安全 为了回答这个问题,我们首先将读/写操作分为3个不同的类别:

  • 直接写入:当您直接将变量/属性设置为给定值时。例如:

  • 间接写入:通过更改对象上的变量来改变对象本身时。例如:

  • 读取:当您对对象进行任何形式的被动读取时(当读取不会导致对象本身发生任何变化时)。例如:


那么属性上的
atomic
属性(不能直接在ivar上设置)确保了什么呢? 它确保直接写入读取是串行的。但是,它不能保护对象在从另一个线程读取时被间接写入,这是不安全的

因此,
原子
属性对于不可变对象(例如
NSString
NSDictionary
&
NSArray
)最有意义。一旦设置了这些对象,您就无法对它们进行变异,因此当
原子时,它们是线程安全的

如果要在可变对象上使用
原子属性
,仍需确保间接写入和读取正确序列化。


非原子属性确保了什么?
什么都没有。

直接写入、间接写入和读取不会发生序列化。因此,速度更快。但是,要确保正确序列化读写操作,完全取决于


那么我该如何连续读写呢? 通过使用并发GCD队列实现这一点确实是正确的

因此,如果您希望在
非原子
ivar上执行此操作,则需要序列化直接写入间接写入读取。如果在
原子属性上执行此操作,则只需序列化间接写入读取

正如您在问题中所提到的,您应该在并发队列上使用
调度屏障
,以便进行任何写入操作(直接或间接)

这是因为
dispatch\u barrier
将等待并发队列上的所有任务在之前完成,并将阻止任何进一步的任务发生,直到它完成因此,写入操作不会受到其他写入或读取操作的任何中断,而多个读取操作可以同时进行

因此,您还应该使用
调度\u sync
将对对象的任何读取通过并发队列进行传递。您不必为读取使用屏障,因为来自不同线程的多个读取不会导致问题

我希望这能为你澄清这个问题


TL;博士 是的,您的方法似乎是正确的。

≠ 线程安全 为了回答这个问题,我们首先将读/写操作分为3个不同的类别:

  • 直接写入:当您直接将变量/属性设置为给定值时。例如:

  • 间接写入:通过更改对象上的变量来改变对象本身时。例如:

  • 读取:当您对对象进行任何形式的被动读取时(当读取不会导致对象本身发生任何变化时)。例如:


那么属性上的
atomic
属性(不能直接在ivar上设置)确保了什么呢? 它确保直接写入读取是串行的。但是,它不能保护对象在从另一个线程读取时被间接写入,这是不安全的

因此,
原子
属性对于不可变对象(例如
NSString
NSDictionary
&
NSArray
)最有意义。一旦设置了这些对象,您就无法对它们进行变异,因此当
原子时,它们是线程安全的

如果要在可变对象上使用
原子属性
,仍需确保间接写入和读取正确序列化。


非原子属性确保了什么?
什么都没有。

直接写入、间接写入和读取不会发生序列化。因此,速度更快。但是,要确保正确序列化读写操作,完全取决于


那么我该如何连续读写呢? 通过使用并发GCD队列实现这一点确实是正确的

因此,如果您希望在
非原子
ivar上执行此操作,则需要序列化直接写入间接写入读取。如果在
原子属性上执行此操作,则只需序列化间接写入读取

正如你在问题中提到的,你应该使用
yourDictionary = [NSMutableDictionary dictionary];
[yourDictionary setObject:@"foo" forKey:@"bar"];
NSString* foo = [yourDictionary objectForKey:@"bar"];