6

在 Android 中,我可以安全地从不同的线程访问和修改原始类型。我用它在我的 OpenGL 绘制循环和在主线程 Android UI 中修改的用户设置之间共享数据。通过将每个设置存储在原始类型中并使每个设置独立于其他值,在不使用锁或 synchronize 关键字的情况下修改所有这些变量是线程安全的。

这在Objective-C中也是如此吗?我读到将 atomic 放在变量上实质上会导致合成的 getter 和 setter 使用锁,类似于在 Java 中使用同步方法。而且我已经读过,这样做的原因是对象在被另一个线程读取时不会被部分修改。

但是原始类型是否可以安全地被部分修改,就像它们在 Java 中一样?如果是这样的话,我似乎可以使用我在 Java 中的旧范式在线程之间共享数据。但是 atomic 关键字对于原语来说是没有意义的,对吗?

我还读到比使用原子变量更健壮和更快的解决方案是,如果从多个线程访问它们,则在使用它们之前复制对象。但我不确定如何做到这一点。非原子对象在被复制的过程中不能被修改,从而破坏副本吗?

4

3 回答 3

6

不能保证原始类型不会被部分修改,因为对原始类型的修改不能保证在 C 中是原子的,并且 Objective-C 从那里继承。C 只保证关注序列点,并且不要求两个序列点之间的处理是原子的——经验法则是每个完整的表达式都是一个序列点。

在实践中,修改原语通常是一个两步过程;修改在寄存器中进行,然后写入内存。写入本身不太可能不是原子的,但也不能保证它何时会发生与修改。即使有volatile资格,提供的唯一保证是在序列点方面。

Apple 通过OSAtomic.h公开了一些用于原子操作的 C 函数,这些函数直接映射到 CPU 为实现并发机制提供的专用原子指令。您可以比通过笨拙的互斥锁更直接地使用其中之一。

Objective-C 中的常见模式有:

  • 不可变对象和功能转换——也有内存管理的原因,但这就是为什么NSString,等与,NSArray等特别不同的部分原因;NSMutableStringNSMutableArray
  • 串行调度队列,可以与复制-修改-替换相结合,通过在队列上复制,到其他地方进行修改,然后跳回队列进行替换;
  • @synchronizeds、sNSConditionLock或其他适当的显式同步机制。

主线程本身是一个串行调度队列,这就是为什么如果你限制自己可以完全忽略并发问题。

于 2013-09-07T00:30:41.583 回答
3

原子合成的@properties 不受并发部分更新的影响。如果需要,访问器方法将在该架构上使用锁。

一般来说,C 中的原始类型对于并发部分更新不一定是安全的。

于 2013-09-07T01:44:12.393 回答
-2

我不相信您可以部分修改原始类型,这是使它们原始的部分原因。你要么修改它,要么不修改。从这个意义上说,我会说它们是线程安全的。

当您说 atomic 关键字对于原始类型毫无意义时,您是正确的。

有人已经在这里尝试过了: Objective-c properties for primitive types

于 2013-09-07T00:23:13.947 回答