这种初始化单例线程的方法是否安全?

时间:2013-05-27 07:24:32

标签: ios thread-safety

这是我们项目中的代码范围,我认为它不是线程安全的,因为范围

if(sharedHelper)
    return sharedHelper;

会引起问题,但我不确定,任何人都可以帮助我吗?

+(id) sharedHelper
{
static MyHelper *sharedHelper = nil;
static dispatch_once_t onceToken;

if(sharedHelper)
    return sharedHelper;

dispatch_once(&onceToken,^{

    sharedHelper = [[self alloc] init];
});

return sharedHelper;
}

1 个答案:

答案 0 :(得分:1)

你认为if阻止可能导致问题是正确的。这就是原因(source):

这一行

[[MyHelper alloc] init];

实际上由三个步骤组成:

  1. 分配内存
  2. 将对象构造为已分配的内存
  3. 将静态变量指向分配的内存地址
  4. 现在,你会期望这些事情从1-3开始。但是,在某些情况下,编译器可能重新排序指令,以便步骤3在步骤2之前发生 -

    sharedHelper = // Step 3
        operator new(sizeof(MyHelper)); // Step 1
    new (sharedHelper) MyHelper; // Step 2
    

    现在,请考虑以下情况:线程1执行步骤1和3并暂停。因此,静态变量指向尚未初始化的内存位置。现在,如果线程2检查if(sharedHelper),它会找到一个非NULL地址,并返回该地址。但是等等,这个地址还没有初始化 - 而BAM,你有一个EXC_BAD_ACCESS。

    同时检查此相关excellent answer