【问题标题】:Does atomic actually mean anything for a synthesized primitive?对于合成的原语来说,原子实际上意味着什么吗?
【发布时间】:2013-09-06 23:34:15
【问题描述】:

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

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

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

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

【问题讨论】:

  • 为什么不用 atomic 声明原始类型以确保线程安全?
  • Atomic vs nonatomic properties 的可能重复项
  • @user1256663 我听说它们很慢,我正在编写一个 OpenGL 应用程序。帧率问题。

标签: objective-c multithreading


【解决方案1】:

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

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

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

Objective-C 中的常见模式有:

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

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

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

      这里已经有人对此进行了尝试: Objective-c properties for primitive types

      【讨论】:

      • 您不能“看到”部分修改的原语类型在大多数架构上,只要原语是缓存对齐的。
      • 取决于原语和架构。例如,一些 ARM 架构使用 8 字节双精度,但正式只承诺 4 字节加载和存储的原子性。
      猜你喜欢
      • 1970-01-01
      • 2019-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-17
      • 2015-10-29
      • 2013-03-13
      • 2012-01-26
      相关资源
      最近更新 更多