在我的Cocoa / iOS应用程序中,我有一个静态double
变量(我们称之为foo
),它必须是:
我正在寻找同步访问foo
的最轻量级方式。
注意:我知道在这些情况下最简单的解决方案通常是调整代码,使得只有一个线程访问变量,因此不需要同步。让我们假设我已经确定在这种情况下不可能限制foo
对单个线程的访问(可能在步骤 1 中采取的操作发生得如此之快/经常不希望线程切换)。请不要回答“限制foo
访问一个帖子”的回答。我正在寻找替代方案。
我目前的理解是,使用volatile
变量是同步访问foo
的最轻量级方式。所以foo
声明如下:
static volatile double foo = 60.0;
后台线程编写代码类似于:
foo = 90.0;
主线程读取代码如下:
double bar = 0.0;
bar = foo;
// use bar here …
<小时/> 一些问题:
foo
之后看到foo
的更新值(假设volatile
被声明为volatile
)? IOW,我是否已经做了足够的工作以确保两个线程将看到彼此的读/写操作结果?double
获取@synchronized
值更快/更轻量级/更可取,而不是像NSLock
块或{{{m}那样的互斥锁1}}。真的吗? IOW,volatile
是这个特殊情况的最佳解决方案吗?答案 0 :(得分:3)
1)否。 volatile
不能替代原子基元。关闭,但不完全。
2)volatile
的问题是,它不是正确的,正如您现在所知道的那样。
理想:您可以访问最新的原子语言功能,例如C11的_Atomic
和/或C ++ 11中的<atomic>
。
如果没有,那么你可以使用64位整数和原子函数,你可以按值读取,然后转移到double
,或者你可以使用简单的pthread_mutex_t
或者甚至是旋转锁(旋转锁非常小心)。
然而......如果你只是将值的更改发布到主线程的运行循环,如果这是一个选项,那可能会更好。
答案 1 :(得分:3)
Cocoa有内置的原语。查看OSAtomic.h
的内容您可以使用OSAtomicCompareAndSwap64Barrier
以原子方式编写(正确对齐和易失)双打。在阅读之前,您可能还需要OSMemoryBarrier
,以确保您也能看到最新的价值。我相信这只适用于64位体系结构,因为32位体系结构可能无法以原子方式读取64位双重体系结构。
答案 2 :(得分:2)
我会使用GCD,创建一个并发调度队列来管理对变量的访问。读者可以简单地
__block double bar;
dispatch_async(foo_queue, ^{ bar = foo; });
并且写入可以使用调度屏障:
dispatch_barrier_async(foo_queue, ^{ foo = someOtherFoo; });
对dispatch_barrier_async
的调用可确保完全执行任何挂起的读取器块,然后执行写入块并在更多读取器块执行之前更新值。
这是Apple在WWDC的一些GCD视频中推荐的模式。
答案 3 :(得分:1)
海湾合作委员会有atomic primitives,这可能就是你所需要的。我不知道在为iOS构建时这些支持有多好,它可能会根据您使用gcc
,llvm-gcc
还是clang
而改变。