Using GCD Queues For Synchronization
This is the second post in a series about Grand Central Dispatch.
In my previous post, we learned that race conditions are a constant problem for asynchronous programs. In short, these are situations where data is simultaneously operated on by multiple threads, resulting in sometimes unpredictable results.
A classic way of solving this issue is by using a mutual exclusion (mutex) object. Here’s an example using the Posix threads API:
#import <Foundation/Foundation.h>
#import <pthread/pthread.h>
// Each player gets 100 gems to start
int playerAGems = 100;
int playerBGems = 100;
// Data structure to hold information about the mutual exclusion object
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *thread1(void *arg) {
// Move 20 gems from player A to player B
pthread_mutex_lock(&mutex); // Wait until we gain access to the mutex
playerAGems -= 20;
playerBGems += 20;
NSLog(@"Player A now has %d gems, and player B has %d gems.", playerAGems, playerBGems);
pthread_mutex_unlock(&mutex); // Unlock the mutex
return NULL;
}
void *thread2(void *arg) {
// Move 50 gems from player B to player A
pthread_mutex_lock(&mutex);
playerAGems += 50;
playerBGems -= 50;
NSLog(@"Player A now has %d gems, and player B has %d gems.", playerAGems, playerBGems);
pthread_mutex_unlock(&mutex);
return NULL;
}
int main() {
pthread_mutex_init(&mutex, NULL); // Initialize the mutex
pthread_t t1; // Data structure to hold information about thread 1
pthread_t t2; // Data structure to hold information about thread 2
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
dispatch_main();
}