pthread_mutex_t VS @synchronized block?

2019-03-28 15:41发布

问题:

static pthread_mutex_t gLock; //global 

pthread_mutex_init(&gLock,NULL); //in init

pthread_mutex_lock(&gLock);
for(int i=0;i<[message count];i++)
CFSetAddValue(mSet, [message objectAtIndex:i]);
pthread_mutex_unlock(&gLock);

My cocoa application is going in not responding mode with pthread_mutex_t.

@synchronized(mSet)
{
for(int i=0;i<[message count];i++)
    CFSetAddValue(mSet, [message objectAtIndex:i]);
}

My application is working fine with synchronized block.

Why?

回答1:

You're comparing a global lock (one lock for all instances) to an object level recursive lock (one lock per instance, which may be acquired multiple times from the same thread). These are not generally interchangeable -- they operate and protect very different from each other.

The good news is, you can use pthread_mutex_t as a recursive lock which is unique to each instance in order to achieve the same degree of protection as @synchronized. Using pthread_mutex_t also makes lock acquisitions much, much faster.

To achieve the same effect as @synchronized using a pthread mutex, declare pthread_mutex_t gLock as an instance variable, then initialize it as a recursive mutex in -init. Finally, destroy the mutex in -dealloc.

Of course, sub- and base- classes may need access to this lock if they relied on the semantics of @synchronized to do the right thing through the object hierarchy.

@synchronized is veeeeeeery slow in comparison to a recursive pthread mutex (last I checked).



回答2:

Justin is right; there is also another detail, however, which is exception handling. From https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html comes this tip:

As a precautionary measure, the @synchronized block implicitly adds an exception handler to the protected code. This handler automatically releases the mutex in the event that an exception is thrown. This means that in order to use the @synchronized directive, you must also enable Objective-C exception handling in your code. If you do not want the additional overhead caused by the implicit exception handler, you should consider using the lock classes.

If [message count] can raise exceptions that could jump over your unlock code and wedge you up.