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);