Мьютекс блокирует только основной поток, когда он достигает своего вызова с помощью директивы @synchronized. - PullRequest
0 голосов
/ 04 января 2012

Я создаю многопоточное приложение, из которого более чем один поток может писать в базу данных sqlite3, включая основной поток. Я объявил статическую публичную переменную, которая будет использоваться для мьютекса:

@implementation Application

#pragma mark -
#pragma mark Static Initializer
static NSString * SubmitChangesLock = nil;

+ (void)initialize {
    [super initialize];
    SubmitChangesLock = [[NSString alloc] initWithString:@"Submit-Changes-Lock"];
}

+ (NSString *)submitChangesLock {
    return SubmitChangesLock;
}

@end

и внутри каждого метода, который должен записывать в базу данных, я использую эту переменную с директивой @synchronized для блокировки раздела, который записывает в базу данных.

- (void)method1FromClass1 {
    @synchronized ([Application submitChangesLock]) {
        // write to the database here...
    }
}

- (void)method2FromClass2 {
    @synchronized ([Application submitChangesLock]) {
        // write to the database here...
    }
}

и все работало нормально, но иногда, когда любой из этих методов вызывается из основного потока, он останавливается, ожидая разблокировки мьютекса, но этого не происходит, и проблема в том, что это происходит только при некоторых вызовах из основного потока и код, который записывает в базу данных, определенно конечен, поэтому я не мог определить, почему основной поток продолжает ожидать разблокировки мьютекса и почему он не разблокируется с самого начала.

Примечание: ни один из других потоков не был заблокирован этим мьютексом, включен только основной.

EDIT: Я попытался заменить директиву @synchronized с помощью executeSelectorOnMainThread: waitUntilDone:

- (void)writeToDatabase {
    // write to the database here...
}
- (void)method2FromClass2 {
    [self performSelectorOnMainThread:@selector(writeToDatabase) withObject:nil waitUntilDone:YES];
}

и он работает просто отлично, но я пытаюсь избежать такой большой нагрузки на основной поток, чтобы не блокировать взаимодействие с пользователем.

Любая помощь будет принята с благодарностью, и большое спасибо заранее.

1 Ответ

1 голос
/ 04 января 2012

В iOS есть функции, которые помогут вам избежать работы с потоками / блокировками в простых и умеренно сложных ситуациях.

Если вы установите NSOperationQueue и setMaxConcurrentOperationCount: на 1, как это предложено deanWombourne, вы можете перенести всю работу в фоновый поток. Есть даже удобный класс (NSInvocationOperation) для простого повторного использования вашего кода из существующих классов в очереди.

Если эти методы, работающие в фоновом режиме, будут влиять на то, что отображается в пользовательском интерфейсе, вы всегда можете использовать performSelectorOnMainThread:withObject:waitUntilDone: для обновления всего, что необходимо.

Если вы сделаете это так, вы никогда не будете блокировать ваш основной поток с активностью БД. Поскольку блокировка основного потока приводит к зависанию пользовательского интерфейса, это, безусловно, способ сделать что-то.

...