Ano*_*dya 29 cocoa multithreading atomic objective-c thread-safety
我搜索并发现不可变是线程安全而可变不是.这可以.但是我得到了误导性的注释,博客,关于线程安全的原子与非原子的答案,请给出答案的解释.
假设有一个名为"name"的原子字符串属性,如果[self setName:@"A"]从线程A调用,[self setName:@"B"]从线程B调用,并[self name]从线程C 调用,则不同线程上的所有操作将串行执行,这意味着如果一个线程正在执行setter或getter,然后其他线程将等待.这使得属性"name"读/写安全,但如果另一个线程D [name release]同时调用,则此操作可能会导致崩溃,因为此处不涉及setter/getter调用.这意味着对象是读/写安全(ATOMIC)但不是线程安全的,因为另一个线程可以同时向对象发送任何类型的消息.
如果属性"name"是非原子的,那么上面例子中的所有线程--A,B,C和D将同时执行,产生任何不可预测的结果.在原子的情况下,A,B或C中的任何一个将首先执行,但D仍然可以并行执行.
你对此的评论将有助于我们......
而我的问题是,"这在可可,原子或非原子中是线程安全的吗?"
jus*_*tin 65
对于ObjC属性 - 都不是线程安全的.
Atomic更能抵抗线程错误.总的来说,这是一个奇怪的默认值.你最喜欢原子的场景很少.原子可以增加正确性的概率,但它太低的水平被认为是正确锁定机制的替代品.因此,如果您需要线程安全性,则仍需要在原子读/写之上使用其他一些同步原语.如果您不需要线程安全(例如,实例是不可变的或仅打算从主线程运行),则atomic将不添加任何内容.
作为耐到线程错误不是"质量" -它用来掩盖真实的线程错误,使他们更难以复制和检测.
另请注意,可变类型与不可变类型实际上并不能保证线程安全.ObjC名称中可以使用'Mutable'来仅指代接口 - 不可变实例的内部实际上可能具有内部可变状态.简而言之,您不能假设具有可变子类的类型是线程安全的.
问题扩大:
假设存在一个名为"name"的原子字符串属性,如果从线程A调用[self setName:@"A"],则从线程B调用[self setName:@"B"],并从中调用[self name]线程C,然后串行执行不同线程上的所有操作,这意味着如果一个线程正在执行setter或getter,那么其他线程将等待.
如果所有线程同时尝试读取和/或写入属性,则一次只有一个线程可以访问,如果属性是原子的,则其他线程将被阻止.如果属性是非原子的,那么它们都将在相同的"时间"对变量进行无保护的读写访问.
如果另一个线程D同时调用[name release],那么此操作可能会导致崩溃,因为此处不涉及setter/getter调用.
正确.
这意味着对象是读/写安全(ATOMIC)但不是线程安全的,因为另一个线程可以同时向对象发送任何类型的消息.
嗯,真的还有更多.常见的例子是:
@interface MONPerson : NSObject
@property (copy) NSString * firstName;
@property (copy) NSString * lastName;
- (NSString *)fullName;
@end
Run Code Online (Sandbox Code Playgroud)
原子或非原子,如果一个线程正在从该实例读取而另一个线程正在写入它,则需要同步机制(例如锁定).您可能最终得到一个MONPerson的firstName和另一个的lastName - 在getter的返回值甚至返回给您之前,该对象可能已经更改,或者这可能发生:
线程A:
p.firstName = @"Rob";
Run Code Online (Sandbox Code Playgroud)
线程B:
p.firstName = @"Robert";
Run Code Online (Sandbox Code Playgroud)
线程A:
label.string = p.firstName; // << uh, oh -- will be Robert
Run Code Online (Sandbox Code Playgroud)
如果属性"name"是非原子的,那么上面例子中的所有线程--A,B,C和D将同时执行,产生任何不可预测的结果.
对 - 初始症状可能是参考计数不平衡(泄漏,过度释放).
在原子的情况下,A,B或C中的任何一个将首先执行,但D仍然可以并行执行.请对此发表评论....
正确.但是如果你看一下上面的例子 - 单独使用原子很少是锁的合适替代品.它必须看起来像这样:
线程A:
[p lock]; // << wait for it… … … …
// Thread B now cannot access p
p.firstName = @"Rob";
NSString fullName = p.fullName;
[p unlock];
// Thread B can now access p
label.string = fullName;
Run Code Online (Sandbox Code Playgroud)
线程B:
[p lock]; // << wait for it… … … …
// Thread A now cannot access p
…
[p unlock];
Run Code Online (Sandbox Code Playgroud)
原子访问器的平均速度比非原子访问器慢20倍.同样,如果您的类需要线程安全并且具有可变状态,那么当它在并发场景中运行时,您可能最终会使用锁.正确的锁定提供了所需的所有保证 - 在这种情况下,原子访问器是多余的,使用原子只会增加CPU时间.关于常规锁定的另一个好处是你拥有所需的所有粒度 - 尽管它通常比用于原子的旋转锁更重,你通常需要更少的获取,所以如果正确使用常规锁定它会非常快.
Asc*_*iom 10
原子保证对变量的原子访问,但它不会使您的代码线程安全.也不是非原子的.
使用"atomic",合成的setter/getter方法将确保始终从getter返回整个值或由setter设置,而不管任何其他线程上的setter活动.因此,如果线程A位于getter的中间,而线程B调用setter,则实际的可行值将返回给A中的调用者.对于非原子,您没有这样的保证.
原子使得以下线程安全.
self.myProperty = value;
Run Code Online (Sandbox Code Playgroud)
要么
id value = self.myProperty
Run Code Online (Sandbox Code Playgroud)
它不会使以下线程安全
[myPorperty addObject:value];
Run Code Online (Sandbox Code Playgroud)
Atomic使得设置或获取属性的线程安全,但它不会调用该属性本身的任何方法线程安全.
设置或获取值可能需要多个CPU指令,这意味着设置或获取可以中途中断,另一个线程可以执行某些操作,使前一个线程的进度在设置中或使值无效.
atomic表示设置或以某种方式获取值,以便它发生在一条不可分割的指令中,因此没有其他线程可以中途退出并搞砸了.
不可变对象是线程安全的简单,因为你不能更改它们,因为你可以从一个不可变对象更改属性,以便除非你使其成为原子,否则该部分将不是安全的.
| 归档时间: |
|
| 查看次数: |
17439 次 |
| 最近记录: |