When dealing with concurrency on the Mac and iPhone, there are some nice classes available, such as NSLock, NSConditionLock and NSRecursiveLock. However, if you need to handle a producer-consumer model with multiple consumers of the same resource, then these locks by themselves won't quite suffice.
Below is the code for a counting semaphore. It is compliant with the NSLocking protocol and is implemented with two mutexes (binary semaphores) and an NSInteger. It will work in a garbage-collected environment.
//CHCountingLock.h #import <Foundation/Foundation.h> #import <pthread.h> @interface CHCountingLock : NSObject <NSLocking> { pthread_mutex_t s1; pthread_mutex_t s2; NSInteger count; } - (id) initWithCount:(NSInteger)initialCount; - (BOOL) tryLock; @end //CHCountingLock.m #import "CHCountingLock.h" @implementation CHCountingLock - (id) init { return [self initWithCount:0]; } - (id) initWithCount:(NSInteger)initialCount { if (self = [super init]) { pthread_mutex_init(&s1, NULL); pthread_mutex_init(&s2, NULL); pthread_mutex_lock(&s2); count = initialCount; } return self; } - (void) dealloc { pthread_mutex_destroy(&s1); pthread_mutex_destroy(&s2); [super dealloc]; } - (void) finalize { pthread_mutex_destroy(&s1); pthread_mutex_destroy(&s2); [super finalize]; } - (void) lock { pthread_mutex_lock(&s1); count--; if (count < 0) { pthread_mutex_unlock(&s1); pthread_mutex_lock(&s2); } pthread_mutex_unlock(&s1); } - (void) unlock { pthread_mutex_lock(&s1); count++; if (count <= 0) { pthread_mutex_unlock(&s2); } else { pthread_mutex_unlock(&s1); } } - (BOOL) tryLock { if (pthread_mutex_trylock(&s1) == 0) { count--; if (count < 0) { pthread_mutex_unlock(&s1); pthread_mutex_lock(&s2); } pthread_mutex_unlock(&s1); return YES; } return NO; } @end
Below is the code for a read/write lock. It is compliant with the NSLocking protocol and is a simple wrapper around a pthread_rwlock_t. It will work in a garbage-collected environment.
//CHReadWriteLock.h #import <Foundation/Foundation.h> #import <pthread.h> @interface CHReadWriteLock : NSObject <NSLocking> { pthread_rwlock_t lock; } - (void) lockForWriting; - (BOOL) tryLock; - (BOOL) tryLockForWriting; @end //CHReadWriteLock.m #import "CHReadWriteLock.h" @implementation CHReadWriteLock - (id) init { if (self = [super init]) { pthread_rwlock_init(&lock, NULL); } return self; } - (void) dealloc { pthread_rwlock_destroy(&lock); [super dealloc]; } - (void) finalize { pthread_rwlock_destroy(&lock); [super finalize]; } - (void) lock { pthread_rwlock_rdlock(&lock); } - (void) unlock { pthread_rwlock_unlock(&lock); } - (void) lockForWriting { pthread_rwlock_wrlock(&lock); } - (BOOL) tryLock { return (pthread_rwlock_tryrdlock(&lock) == 0); } - (BOOL) tryLockForWriting { return (pthread_rwlock_trywrlock(&lock) == 0); } @end