Ios 块变量赋值后立即读取是否线程安全?

Ios 块变量赋值后立即读取是否线程安全?,ios,objective-c,synchronization,thread-safety,objective-c-blocks,Ios,Objective C,Synchronization,Thread Safety,Objective C Blocks,在此之后阅读httpResponse是否安全?信号量等待块竞争执行。如果没有错误,是否会立即看到分配,或者是否必须在块外同步或创建内存屏障 等待信号量是否会隐式执行某些同步,从而使_块变量可以安全地立即读取。如果这是用Java中的Thread.join()而不是信号量来完成的,那么它将是安全的,因为它保证了与“块”中的赋值的“发生在之前”关系 信号量锁实质上强制当前正在运行的线程停止执行,直到它收到足够的解锁信号继续 在允许信号量继续执行之前,您定义的变量在其他线程上被修改,因此您的赋值应该已经

在此之后阅读
httpResponse
是否安全?信号量等待块竞争执行。如果没有错误,是否会立即看到分配,或者是否必须在块外同步或创建内存屏障


等待信号量是否会隐式执行某些同步,从而使_块变量可以安全地立即读取。如果这是用Java中的
Thread.join()
而不是信号量来完成的,那么它将是安全的,因为它保证了与“块”中的赋值的“发生在之前”关系

信号量锁实质上强制当前正在运行的线程停止执行,直到它收到足够的解锁信号继续


在允许信号量继续执行之前,您定义的变量在其他线程上被修改,因此您的赋值应该已经安全发生。

看来
dispatch\u semaphore\u wait
也是一个内存障碍,因此可以安全地读取该值。

严格来说,此代码将在执行线程(可能是主线程)上阻塞,直到信号量锁发出信号。这么简单的回答,是的,它应该工作,但它不是最佳实践,因为它阻塞了主线程

详细回答:

是的,信号量将确保在填充之前不会访问_块捕获的存储。但是,调用线程将被等待阻塞,直到阻塞完成。这并不理想-正常的UI任务,如确保活动指示器旋转不会发生

最好的做法是,在主对象完成后,将块信号发送给主对象(可能使用对主队列的dispatch\u async调用),并且仅在完成后访问它。如果会话任务失败(例如,由于网络连接),则调用线程可能会阻塞,直到使用超时错误调用完成处理程序为止,这一点尤其正确。在用户看来,这就像应用程序已经冻结一样,他们除了杀死应用程序之外,实在无能为力

有关使用块的详细信息,请参见:

对于数据会话任务的最佳实践,尤其是:


执行顺序不能保证内存可见性。分配仍然可以位于不同CPU核心的缓存中,并且对父线程不可见。这就是为什么你需要某种记忆障碍。仅仅因为您在赋值后读取了值,就看不到最新的值。整个过程已经在后台线程中,所以我想同步调用NSURLSession。再一次,等待线程!=您可以看到它所做的更改。除非在读取值之前存在内存障碍,否则不能保证您会看到赋值。等待是不够的。
__block NSHTTPURLResponse *httpResponse;

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    if (!error) 
        httpResponse = (NSHTTPURLResponse *)response;
    }

    dispatch_semaphore_signal(semaphore);
}];
[task resume];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);