Поскольку следующий код является довольно распространенным шаблоном в Objective-C для создания экземпляра и обеспечения его потокобезопасности. Однако эта потокобезопасность основана на одном важном условии, что локальная статическая переменная является потокобезопасной, что гарантируется компилятором, что означает, что статический указатель _sharedCache будет гарантированно создан в потокобезопасном режиме, однако я не могу узнайте любую документацию, упоминающую об этом. Кто-нибудь может предоставить мне более уверенное доказательство? (Поскольку люди здесь сосредотачиваются на изменяемом наборе, который я использовал в начале, поэтому я просто меняю его на NSCache, это действительно не главное. Я говорю о безопасности потоков при создании локального статического указателя здесь (не экземпляр, на который указывает этот указатель))
+ (NSCache*)sharedCache {
static NSCache* _sharedCache = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedCache = [[NSCache alloc] init];
});
return _sharedCache;
}
На всякий случай, если я не ясно описал условие гонки, считайте, что два потока одновременно вызывают этот API и одновременно проверяют, существует ли этот статический указатель _sharedCache, если нет, они сами создадут новый статический указатель. Тогда это могут быть два статических указателя NSMutableSet здесь, даже dispatch_once гарантировал, что инициализация экземпляра произошла только один раз, то есть только для одного из этих двух статических указателей, а затем после блока dispatch_once первый вызывающий объект получает удовлетворительный результат, но второй вызывающий абонент просто возвращает нулевой указатель;
Рассмотрим этот случай, A и B - два потока, ввели этот код одновременно, A проверил статический указатель "_sharedSet" здесь и обнаружил, что здесь нет такого указателя (указатель является экземпляром unsigned long), поэтому он создает его и присваивает 0 к нему, теперь этот указатель хранится в адресе памяти (0xAAAAAAAA), одновременно B сделал то же самое, создал статический указатель в куче, но с адресом памяти (0xBBBBBBBB), затем dispatch_once заблокировал оба потока, пока они не закончатся, поэтому он назначил новое значение указателя с этим созданным экземпляром NSSet и присвоило это значение адресу 0xAAAAAAAA, однако значение по адресу 0xBBBBBBBB по-прежнему равно 0, потому что его никто не обновляет, поэтому поток B просто возвращает nil. Итак, в основном мой вопрос не о сомнении в dispatch_once, а о безопасности потоков при создании локальной статической переменной, это действительная проблема на C++, пока C11 не разрешил ее. Мне просто интересно, заметил ли Clang эту проблему.
И этот вопрос на самом деле не о dispatch_once, а о локальной статической переменной, быть конкретной переменной, не являющейся объектом, как упомянутый здесь указатель, или просто изменить способ спросить, если следующий код, вызванный в соревновательном потоков, будет ли этот "_intBuffer" гарантировать только один экземпляр в куче?
+(int)sharedIntBuffer {
static int _intBuffer = 0;
return _intBuffer;
}