Cocoa:最轻量级的同步访问双重方式?

时间:2012-08-23 17:00:04

标签: c cocoa thread-safety

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

  1. 我的应用程序的一部分在后台线程上更新
  2. 通过主线程上的我的应用程序的另一部分阅读
  3. 我正在寻找同步访问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被声明为volatile)? IOW,我是否已经做了足够的工作以确保两个线程将看到彼此的读/写操作结果?
    2. 我假设在这种情况下使用double获取@synchronized值更快/更轻量级/更可取,而不是像NSLock块或{{{m}那样的互斥锁1}}。真的吗? IOW,volatile是这个特殊情况的最佳解决方案吗?

4 个答案:

答案 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构建时这些支持有多好,它可能会根据您使用gccllvm-gcc还是clang而改变。