在启用了ARC的iOS上使用OSAtomicCompareAndSwapPtr

时间:2012-09-12 08:28:47

标签: ios automatic-ref-counting compare-and-swap

预先自动引用计数,你可以在Objective-c中进行适当的指针转换,以允许你使用bool OSAtomicCompareAndSwapPtr(void * oldValue,void * newValue,void * volatile * theValue);在处理多线程访问时尝试以原子方式交换指针。

在ARC下,这些指针强制转换无效。在ARC for iOS下是​​否有可用的等效原子指针交换?如果这个替代方案仍然可用,我希望避免更昂贵的锁定。

2 个答案:

答案 0 :(得分:0)

如果满足一个条件,您可以轻松地使用它,也许如果您愿意玩游戏。

创建一个新文件,在Build Phase中将其标记为不使用ARC,并将此交换放入一个小C函数中。在函数的顶部获取对象的retainCounts,如果它们相等(并且你有理由相信它们不在自动释放池中),你可以交换它们,因为ARC将确保每个都有适当的版本。

如果他们不平等,那么你可以通过更改保留计数来玩游戏。

答案 1 :(得分:0)

免责声明:此答案中的代码未经过测试!

首先,我想提一下大多数指针使用并不需要比较和交换。 C指针读取和写入本身是原子的。有关详细信息,请参阅this SO answer。 ARM也是如此。因此,如果您实现原子getter和setter,您只需要一个内存屏障来保证其他线程看到完全初始化的对象:

NSObject * global;
NSObject * get() { return global; }
void set(NSObject * value) { OSMemoryBarrier(); global = value; }

现在回到这个问题,因为谁知道,也许有比较和交换对象的真正用途。演员阵容仍然有可能,你现在只是以不同方式宣布:

NSString * a = @"A";
NSObject * b = @"B";
OSAtomicCompareAndSwapPtrBarrier(
    (__bridge void *)a,
    (__bridge void *)b,
    (__bridge void * *)&a);

但是,此代码存在问题:字符串@"A"丢失了引用,@"B"被引用两次,而不知道ARC。因此,@"A"会泄漏,并且程序在离开作用域时可能会崩溃,因为@"B"将被释放两次,同时只有1的保留计数器。

我认为唯一的选择是使用Core Foundation对象。您可以使用NSObject与CFType进行免费桥接的事实。我无法找到任何关于此的明确文件,但它遵循常识和实际证据。所以例如可以实现单例:

CFTypeRef instance;
Thingamabob * getInstance() {
  if (!instance) {
    CFTypeRef t = (__bridge_retained CFTypeRef)[Thingamabob new];
    if (!OSAtomicCompareAndSwapPtrBarrier(NULL, t, &instance)) {
      CFRelease(t);
    }
  }
  return (__bridge Thingamabob *)instance;
}