Objective C atomic property thread safe
我读了几篇关于原子的文章,并编写了一个演示来验证线程安全,就像这样
1 | @property(atomic,assign) NSInteger sum; |
/然后这样做
1 2 3 4 5 6 7 | for (NSInteger i = 0; i<1000; i++) { dispatch_queue_t queue = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ self.sum++; }); } |
将属性"sum"设置为原子属性;启动1000个并发线程添加一个;
我虽然结果是1000,但不是,如果我加一个nslock来包装self.sum++,结果是1000;
有人帮我解释这个吗?
这有几个层次。
首先,声明的属性主要只是声明访问器方法的快捷方式。如果不提供自己的实现,则默认情况下会发生属性的编译器合成,定义这些方法和实例变量以支持属性。
所以,这个:
1 | @property(atomic,assign) NSInteger sum; |
基本上就是这样:
1 2 | - (NSInteger) sum; - (void) setSum:(NSInteger)value; |
属性的合成生成实例变量和这些方法的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 | @implementation ... { NSUInteger _sum; } - (NSInteger) sum { // ... } - (void) setSum:(NSInteger)value { // ... } |
对于一个原子属性,
对于具有复合类型的属性,如
接下来,使用点语法(例如
1 | [self setSum:[self sum] + 1]; |
因此,您的语句首先涉及一个调用
简而言之,原子性不是线程安全性。认为这是概念上的错误。这只是原子性。它确实防止了当多个线程同时访问同一个属性而不是所有属性时可能发生的一种损坏。
尝试一下:
1 2 3 4 5 6 7 8 9 | dispatch_queue_t queue = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT); for (NSInteger i = 0; i<1000; i++) { dispatch_async(queue, ^{ NSLock *aLock = [[NSLock alloc] init]; [aLock lock]; self.sum++; [aLock unlock]; }); } |