Saturday, October 25, 2014

Unix Prog: Mutexes

1. mutex
A mutex is basically a lock that we set(lock) before accessing a shared resource and release(unlock) when we're done. While it is set, any other thread tries to set it will block until we release it.

system call definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/pthread.h  
 ......  
 /* Initialize a mutex. */  
 extern int pthread_mutex_init (pthread_mutex_t *__mutex,  
                 const pthread_mutexattr_t *__mutexattr)  
    __THROW __nonnull ((1));  
   
 /* Destroy a mutex. */  
 extern int pthread_mutex_destroy (pthread_mutex_t *__mutex)  
    __THROW __nonnull ((1));  
   
 /* Try locking a mutex. */  
 extern int pthread_mutex_trylock (pthread_mutex_t *__mutex)  
    __THROWNL __nonnull ((1));  
   
 /* Lock a mutex. */  
 extern int pthread_mutex_lock (pthread_mutex_t *__mutex)  
    __THROWNL __nonnull ((1));  
   
 /* Unlock a mutex. */  
 extern int pthread_mutex_unlock (pthread_mutex_t *__mutex)  
    __THROWNL __nonnull ((1));  
 ......  

Before using a mutex, we need to either initialize it to PTHREAD_MUTEX_INITIALIZER or call pthread_mutex_init.

If we allocate the mutex dynamically, when we need to call pthread_mutex_destroy before freeing the memory.

pthread_mutex_trylock behaves conditionally:
1) if mutex is locked, it will return EBUSY without blocking, without locking the mutex.
2) if mutex is not locked, it will lock the mutex without blocking.

2. Example:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<pthread.h>  
   
 int value = 0;  
 pthread_mutex_t lock;  
   
 void* thr_fn1(void *arg)  
 {  
  pthread_mutex_trylock(&lock);  
  printf("thread 1 trylocked\n");  
  value++;  
  sleep(3);  
  printf("thread 1 unlocked\n");  
  pthread_mutex_unlock(&lock);  
 }  
   
 int main(int argc, char* argv[])  
 {  
  // Initialize mutex  
  if(pthread_mutex_init(&lock, NULL) != 0) {  
   printf("mutex init failed.\n");  
   exit(1);  
  }  
   
  // launch the thread 1  
  pthread_t tid1;  
  if(pthread_create(&tid1, NULL, thr_fn1, NULL) != 0) {  
   printf("pthread_create failed.\n");  
   exit(2);  
  }  
   
  // main thread sleep 2 seconds to let thread 1 run firstly  
  sleep(2);  
   
  printf("waiting for thread 1 lock...\n");  
  pthread_mutex_lock(&lock);  
  printf("main thread locked\n");  
  value++;  
  pthread_mutex_unlock(&lock);  
   
  printf("value = %d\n", value);  
  exit(0);  
 }  

shell:
Firstly, main thread fell asleep to let thread 1 run firstly. Thread 1 "trylock" the mutex, and sleep 3 seconds. During this period, main thread waked up and and lock the mutex, but at this time, thread 1 still doesn't release the lock.
After 1 second, thread 1 wake up and release the lock. Main thread acquire the lock.
 ubuntu@ip-172-31-23-227:~$ ./trylock.out  
 thread 1 trylocked  
 waiting for thread 1 lock...  
 thread 1 unlocked  
 main thread locked  
 value = 2  

===============================================================
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<pthread.h>  
   
 int value = 0;  
 pthread_mutex_t lock;  
   
 void* thr_fn1(void *arg)  
 {  
  if(pthread_mutex_trylock(&lock) == 0) {  
   printf("thread 1 trylocked\n");  
   value++;  
   printf("thread 1 unlocked\n");  
   pthread_mutex_unlock(&lock);  
  }  
  else {  
   printf("thread trylock failed, but it doesn't block!\n");  
  }  
 }  
   
 int main(int argc, char* argv[])  
 {  
  // Initialize mutex  
  if(pthread_mutex_init(&lock, NULL) != 0) {  
   printf("mutex init failed.\n");  
   exit(1);  
  }  
   
  // Main thread lock the mutex  
  pthread_mutex_lock(&lock);  
  printf("main thread locked\n");  
  value++;  
   
  // launch the thread 1  
  pthread_t tid1;  
  if(pthread_create(&tid1, NULL, thr_fn1, NULL) != 0) {  
   printf("pthread_create failed.\n");  
   exit(2);  
  }  
   
  // Sleep 2 seconds to let thread 1 execute  
  sleep(2);  
  pthread_mutex_unlock(&lock);  
   
  printf("value = %d\n", value);  
  exit(0);  
 }  

shell:
Firstly, main thread lock the mutex. And then launch the thread 1, who will trylock the mutex, but at this time, mutex is already locked by main thread, so trylock failed, but it doesn't block there, it keep executing and output:
"thread trylock failed, but it doesn't block!". Then thread 1 is finished.

After 2 seconds, main thread wake up and release the mutex.
 ubuntu@ip-172-31-23-227:~$ ./trylock.out  
 main thread locked  
 thread trylock failed, but it doesn't block!  
 value = 1  

No comments:

Post a Comment