以下是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.
}
}
Run Code Online (Sandbox Code Playgroud)
我将不得不背离公认的答案。对不起。虽然目标 c 不保证声明为非原子的 BOOL 属性实际上是原子的,但我不得不猜测您最关心的硬件(所有 iOS 和 macos 设备)有指令以原子方式执行字节读取和存储。因此,除非 Apple 推出运行在 IBM 微控制器上的 Road Light OS,该微控制器具有 5 位宽的总线以通过 10 位字节发送,否则您也可以在需要原子 BOOL 的情况下使用非原子 BOOL。该代码无法移植到 Road Light OS,但如果您可以牺牲代码的未来安全性,非原子性对于此用例来说很好。我敢肯定会有一些顽固的人,所以这会带来分解原子/非原子情况下合成的 BOOL getter 和 setter 的挑战,看看是什么' s 的区别。至少在 ARM 上。
您从中得出的结论可能是
当两个线程“同时”将 BOOL 设置为 YES 时会发生什么?
那么它的值将是YES. 如果线程将相同的值写入相同的内存位置,则该内存位置将具有该值,无论是否是原子的都不起作用。仅当两个线程向同一内存位置写入不同的值,或者一个线程向该位置写入数据而另一个线程正在读取该位置时,它才会发挥作用。
Objective C 中 BOOL 读/写是原子的吗?
如果您的硬件是运行 macOS 的 Macintosh,则适用。BOOL在uint32_tPPC 系统和charIntel 系统上,写入这些数据类型在各自的系统上是原子的。
但 Obj-C 语言并没有做出这样的保证。在其他系统上,这取决于您使用的编译器以及如何BOOL为该平台定义。大多数编译器(gcc,clang,...)保证写入 -size 的变量int始终是原子的,其他大小是否是原子的取决于 CPU。
请注意,原子性与线程安全不同。写aBOOL不是内存障碍。编译器和 CPU 可能会围绕BOOL写入重新排序指令:
a = 10;
b = YES;
c = 20;
Run Code Online (Sandbox Code Playgroud)
不保证指令按该顺序执行。事实上,这b并不YES意味着a是 10。编译器和 CPU 可以根据需要随意调整这三个指令,因为它们彼此不依赖。显式原子指令以及锁、互斥锁和信号量通常是内存屏障,这意味着它们指示编译器和 CPU 不要将位于该操作之前的指令移至其之外,也不要将位于该操作之后的指令移至其之前(这是一个硬边界,该指令可能无法通过)。
另外,缓存一致性也无法得到保证。即使在您将 a 设置BOOL为之后,其他一些线程仍可能在有限的时间内YES将其视为。NO内存屏障操作通常也是确保系统中所有线程/核心/CPU 之间缓存同步的操作。
在这里添加一些真正有用的东西,这就是如何确保设置布尔值是原子的,并在 2020 年使用 C11 充当内存屏障,这也适用于 Obj-C 代码:
#import <stdatomic.h>
// ...
volatile atomic_bool b = true;
// ...
atomic_store(&b, true);
// ...
atomic_store(&b, false);
Run Code Online (Sandbox Code Playgroud)
该代码不仅保证对 bool 的原子写入(系统将为其选择适当的类型),它还将充当内存屏障(顺序一致)。
要从另一个线程原子地读取布尔值,您可以使用
bool x = atomic_load(&b);
Run Code Online (Sandbox Code Playgroud)
您还可以使用atomic_load_explicitandatomic_store_explicit并传递显式内存顺序,这使您可以更细粒度地控制允许哪种内存重新排序,不允许哪些内存重新排序。
在这里详细了解您的可能性:
http://llvm.org/docs/Atomics.html
请务必阅读“优化器注释”以了解允许哪些内存重新排序。如果有疑问,请始终使用顺序一致(memory_order_seq_cst如果未指定,则这是默认值)。它不会带来最快的性能,但它是最安全的选择,如果你知道自己在做什么,你真的应该只使用其他东西。
| 归档时间: |
|
| 查看次数: |
6382 次 |
| 最近记录: |