当两个线程同时将BOOL设置为YES时会发生什么?
答案 0 :(得分:7)
以下是Jacko建议的解决方案的代码
将volatile
uint32_t
与OSAtomicOr32Barrier
和OSAtomicAnd32Barrier
#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,无论哪个线程首先进入。
答案 2 :(得分:4)
我不得不偏离接受的答案。抱歉。 而objective c不保证BOOL属性声明为非原子 实际上是原子的我不得不猜你最硬的硬件 关心(所有iOS和macos设备)都有指令来执行字节读取和原子存储。因此,除非Apple推出Road Light OS 在具有5位宽总线的IBM微控制器上发送10位字节 你也可以在调用原子BOOL的情况下使用非原子BOOL。代码不能移植到Road Light OS,但如果可以的话 为了这个用例,牺牲代码的未来保护非原子性。 我确定s.o上有坚强的人。这会引起挑战,为原子/非原子情况拆解合成的BOOL吸气剂和定位器,看看有什么区别。至少在ARM上。
你可能会从中获取这个
答案 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;
不能保证指令按该顺序执行。 B
是YES
的事实并不意味着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_explicit
和atomic_store_explicit
并传递一个显式的内存顺序,这使您可以更细粒度地控制哪种内存允许重新排序,哪些不允许。
在此处详细了解您的可能性:
http://llvm.org/docs/Atomics.html
请始终阅读“优化器说明”,以了解在这种情况下允许进行哪种内存重新排序,而哪些不允许。如有疑问,请始终使用SequentiallyConsistent(memory_order_seq_cst
,如果未指定,则为默认值)。这样做不会带来最快的性能,但这是最安全的选择,实际上,只有在知道自己在做什么的情况下,才应该使用其他东西。