BOOL是否在Objective C中读/写原子?

时间:2010-02-14 02:41:57

标签: objective-c atomic boolean

当两个线程同时将BOOL设置为YES时会发生什么?

4 个答案:

答案 0 :(得分:7)

以下是Jacko建议的解决方案的代码 将volatile uint32_tOSAtomicOr32BarrierOSAtomicAnd32Barrier

一起使用
#import <libkern/OSAtomic.h>

volatile uint32_t _IsRunning;

- (BOOL)isRunning {
    return _IsRunning != 0;
}

- (void)setIsRunning:(BOOL)allowed {

    if (allowed) {
        OSAtomicOr32Barrier(1, & _IsRunning); //Atomic bitwise OR of two 32-bit values with barrier
    } else {
        OSAtomicAnd32Barrier(0, & _IsRunning); //Atomic bitwise AND of two 32-bit values with barrier.
    }
}

答案 1 :(得分:6)

没有。如果没有锁定结构,在Objective C中读/写任何类型变量都不是原子的。

如果两个线程同时向BOOL写入YES,则结果为YES,无论哪个线程首先进入。

请参阅:Synchronizing Thread Execution

答案 2 :(得分:4)

我不得不偏离接受的答案。抱歉。 而objective c不保证BOOL属性声明为非原子 实际上是原子的我不得不猜你最硬的硬件 关心(所有iOS和macos设备)都有指令来执行字节读取和原子存储。因此,除非Apple推出Road Light OS 在具有5位宽总线的IBM微控制器上发送10位字节 你也可以在调用原子BOOL的情况下使用非原子BOOL。代码不能移植到Road Light OS,但如果可以的话 为了这个用例,牺牲代码的未来保护非原子性。 我确定s.o上有坚强的人。这会引起挑战,为原子/非原子情况拆解合成的BOOL吸气剂和定位器,看看有什么区别。至少在ARM上。

你可能会从中获取这个

  1. 你可以将BOOL属性声明为原子,它不会花费你一分钱 所有HW iOS和macOS本质上都支持。
  2. 记忆障碍与原子性正交
  3. 你绝对不应该使用4字节属性来存储布尔值 除非你进入[非常]模糊的逻辑。 它既愚蠢又浪费,你不想成为Java程序员的克隆人, 谁不能告诉双人的浮动,或者你呢?
  4. BOOL变量(显然不支持原子/非原子装饰器 在一些狭窄的总线架构中,目标C会不会是原子的 不管怎么说(微控制器有或没有一些微型操作系统我认为是C&amp;汇编领域。他们通常不需要行李箱 objc运行时会带来)

答案 3 :(得分:1)

当两个线程“同时”将BOOL设置为YES时会发生什么?

则其值为YES。如果线程将相同的值写入相同的内存位置,则该内存位置将具有该值,无论该值是否为原子都不会起作用。仅当两个线程向同一内存位置写入不同的值,或者一个线程在另一个线程正在从其读取数据时向其写入数据时,它才起作用。

BOOL是在Objective C中读/写原子吗?

这是如果您的硬件是运行macOS的Macintosh。 BOOL在PPC系统上是uint32_t,在Intel系统上是char,在它们各自的系统上写这些数据类型是原子的。

但是,Obj-C语言没有做出任何保证。在其他系统上,这取决于您使用的编译器以及如何为该平台定义BOOL。大多数编译器(gcc,clang等)都保证写int-size的变量始终是原子的,而其他大小是否是原子的则取决于CPU。

请注意,atomic与线程安全不同。编写BOOL不是内存障碍。编译器和CPU可能会在BOOL写操作附近对指令重新排序:

a = 10;
b = YES;
c = 20;

不能保证指令按该顺序执行。 BYES的事实并不意味着a是10。编译器和CPU可以根据需要随意调整这三个指令,因为它们彼此不依赖。显式的原子指令以及锁,互斥和信号量通常是内存屏障,这意味着它们指示编译器和CPU在该操作之后或相反之前不要移动该指令。

也不能保证高速缓存的一致性。即使在将BOOL设置为YES之后,其他线程仍可能在有限的时间内将其视为NO。内存屏障操作通常也是确保缓存同步的操作。

还要添加一些真正有用的东西,这是如何确保使用C11设置布尔值是原子的并在2020年充当内存屏障,这也将在Obj-C代码中起作用:

#import <stdatomic.h>

// ...

volatile atomic_bool b = true;

// ...

atomic_store(&b, true);

// ...

atomic_store(&b, false);

是的,真的很简单。该代码不仅可以保证原子写入bool(系统将在可能的情况下为该布尔类型选择适当的类型),而且还可以充当内存屏障(SequentiallyConsistent)。

要从另一个线程自动读取布尔值,请使用

bool x = atomic_load(&b);

您还可以使用atomic_load_explicitatomic_store_explicit并传递一个显式的内存顺序,这使您可以更细粒度地控制哪种内存允许重新排序,哪些不允许。

在此处详细了解您的可能性:

http://llvm.org/docs/Atomics.html

请始终阅读“优化器说明”,以了解在这种情况下允许进行哪种内存重新排序,而哪些不允许。如有疑问,请始终使用SequentiallyConsistent(memory_order_seq_cst,如果未指定,则为默认值)。这样做不会带来最快的性能,但这是最安全的选择,实际上,只有在知道自己在做什么的情况下,才应该使用其他东西。