Независимо от того, является ли переменная экземпляром переменной или глобальной переменной, если несколько потоков могут выполнять запись в эту переменную одновременно, вам необходимо заблокировать этот раздел кода. Например,
-(IBAction)loadPagesWithGraphics:(id)sender{
@synchronized(self) {
if (imageLoaderBusy) return;
imageLoaderBusy = YES;
}
NSAutoreleasePool *arPool = [[NSAutoreleasePool alloc] init];
// Load Images
imageLoaderBusy = NO;
[arPool release];
}
Допустим, два выполнения этого метода происходят одновременно в потоках A и B, и A сначала получает блокировку, поэтому поток B ожидает снятия блокировки. С точки зрения A, imageLoaderBusy == NO
, поэтому он не возвращает, устанавливает imageLoaderBusy = YES
и снимает блокировку.
Поскольку блокировка снята, поток B может начать выполнение. Он проверяет imageLoaderBusy
и, поскольку поток A установил его на YES
, метод немедленно возвращается в поток B.
Поток A приступает к загрузке изображений и устанавливает imageLoaderBusy
в NO
.
Обратите внимание, что это означает, что если метод вызывается снова в каком-то потоке, он будет выполнен и снова загрузит изображения . Я не уверен, что это ваше намерение; если это не так, вам потребуется еще одна проверка, чтобы определить, загружены ли уже изображения. Например,
-(IBAction)loadPagesWithGraphics:(id)sender{
if (imagesHaveBeenLoaded) return;
@synchronized(self) {
if (imageLoaderBusy) return;
imageLoaderBusy = YES;
}
NSAutoreleasePool *arPool = [[NSAutoreleasePool alloc] init];
// Load Images
[arPool release];
imageLoaderBusy = NO; // not strictly necessary
imagesHaveBeenLoaded = YES;
}
Вам не нужно иметь весь метод внутри блока @synchronize
. Фактически, критические секции обычно должны быть небольшими, особенно если блокировка применяется ко всему объекту (self
). Если весь метод был критическим разделом, поток B должен был бы подождать, пока все изображения загрузятся, прежде чем заметить, что другой поток уже занят / уже загрузил изображения.