A mutex blocks only the main thread when it reaches its call with the @synchronized directive

时光毁灭记忆、已成空白 提交于 2019-12-25 09:00:35

问题


I'm building a multithreaded application, from which more than one thread can write to an sqlite3 database including the main thread. I declared a static public variable to be used for the mutex:

@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

and inside each method that should write to a database I'm using that variable with the @synchronized directive to lock the section that write to the database.

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

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

and everything worked fine but sometimes when any of those methods gets called from the main thread it freezes waiting for the mutex to be unlocked again but it didn't and the problem is that this only occurs on some calls from the main thread and the code that writes to the database is definitely finite so I could not determine why the main thread keeps waiting for mutex to be unlocked and why it's not getting unlocked on the first place.

Note: none of the other threads got blocked by this mutex, only the main on.

EDIT: I tried to replace the @synchronized directive using the performSelectorOnMainThread:waitUntilDone:

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

and it's working just fine but I'm trying to avoid so much load on the main thread not to block the user interaction.

Any help would be greatly appreciated, and many thanks in advance.


回答1:


There are features in iOS which exist to help you avoid dealing with threads/locking in simple to moderately complex situations.

If you set up an NSOperationQueue and setMaxConcurrentOperationCount: to 1, as suggested by deanWombourne, you can offload all the work to a background thread. There's even a handy class (NSInvocationOperation) to easily reuse your code from existing classes in a queue.

If these methods that are running in the background will affect what's appearing in the UI, you can always use performSelectorOnMainThread:withObject:waitUntilDone: to update whatever is necessary.

If you do it like this, you'll never be blocking your main thread with DB activity. Since blocking the main thread freezes the UI, this is definitely the way to do things.



来源:https://stackoverflow.com/questions/8726090/a-mutex-blocks-only-the-main-thread-when-it-reaches-its-call-with-the-synchroni

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!