3

在我的 Cocoa/iOS 应用程序中,我有一个静态double变量(我们称之为foo),它必须是:

  1. 由我的应用程序的一部分在后台线程上更新
  2. 由我的应用程序的另一部分在主线程上读取

我正在寻找最轻量级的方式来同步对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 …


一些问题:

  1. 是否保证主线程foo在将其写入后台线程之后看到更新的值(假设foo已声明volatile)?IOW,我是否已经做了足够的工作来确保两个线程将看到彼此的读/写操作的结果?
  2. 我假设在这种情况下使用volatilefordouble值更快/更轻量/更可取,而不是像@synchronized块或NSLock. 真的吗?IOW,是volatile这种特殊情况的最佳解决方案吗?
4

4 回答 4

3

1)没有volatile不是这里的原子原语的替代品。关闭,但不完全。

2)问题volatile是,它不正确,正如您现在所知道的。

理想:您可以访问最新的原子语言功能,例如_AtomicC11 和/或<atomic>C++11。

如果不是,那么您可以使用 64 位整数和原子函数,按值读取,然后转移到 a double,或者您可以使用简单的pthread_mutex_t甚至是自旋锁(请注意自旋锁)。

但是……如果您只是将值的更改发布到主线程的运行循环,如果这是一个选项,它可能会更好。

于 2012-08-23T17:09:39.850 回答
3

Cocoa 对此有内置的原语。查看OSAtomic.h的内容

您可以使用OSAtomicCompareAndSwap64Barrier以原子方式编写(正确对齐和易失的)双精度数。您可能还需OSMemoryBarrier要先阅读以确保您也看到最新值。我相信这只适用于 64 位架构,因为 32 位架构可能不会以原子方式读取 64 位双精度。

于 2012-08-23T19:29:30.057 回答
2

我会为此使用 GCD,创建一个并发调度队列来管理对变量的访问。读者可以简单

__block double bar;
dispatch_async(foo_queue, ^{ bar = foo; });

并且写入可以使用调度屏障:

dispatch_barrier_async(foo_queue, ^{ foo = someOtherFoo; });

调用dispatch_barrier_async确保所有待处理的读取器块都被完全执行,然后写入块将被执行并在任何更多的读取器块可以执行之前更新值。

这是 Apple 在 WWDC 的一些 GCD 视频中推荐的模式。

于 2012-08-23T18:15:40.333 回答
1

GCC 有可能是你需要的原子原语。我不知道在为 iOS 构建时对这些的支持有多好,它可能会根据您使用gccllvm-gccclang.

于 2012-08-23T17:11:56.207 回答