Saturday, November 1, 2014

Unix Prog: Synchronization Attributes(2)

1. The way to avoid the recursive mutex

mutex.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
 #include<pthread.h>  
   
 int value = 0;  
 pthread_mutex_t mutex;  
 pthread_mutexattr_t m_attr;  
   
 void func_value(void)  
 {  
  // This function process the shared data, before calling this function  
  // mutex must be locked.  
  value++;  
 }  
   
 void func_2(void)  
 {  
  pthread_mutex_lock(&mutex);  
  func_value();  
  pthread_mutex_unlock(&mutex);  
 }  
   
 void func_1(void)  
 {  
  pthread_mutex_lock(&mutex);  
  func_value();  
  pthread_mutex_unlock(&mutex);  
 }  
   
 int main(int argc, char* argv[])  
 {  
  //Initialize mutex attribute  
  pthread_mutexattr_init(&m_attr);  
  pthread_mutexattr_settype(&m_attr, PTHREAD_MUTEX_NORMAL);  
   
  //Initialize mutex  
  if(pthread_mutex_init(&mutex, &m_attr) != 0) {  
   printf("pthread_mutex_init error!\n");  
   exit(1);  
  }  
   
  func_1();  
  func_2();  
   
  printf("value: %d\n", value);  
   
  // Destory the mutex and mutex attribute object  
  pthread_mutexattr_destroy(&m_attr);  
  pthread_mutex_destroy(&mutex);  
 }  

shell:
We can extract the common code to update the value, and whenever before updating the value, we should lock the mutex with the caller.
 ubuntu@ip-172-31-23-227:~$ ./mutex.out  
 value: 2  

2. Example of usage of recursive lock
mutex.c
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
 #include<pthread.h>  
 #include<time.h>  
 #include<sys/time.h>  
   
 #define SECTONSEC 1000000000  
 #define USECTONSEC 1000  
   
 struct to_info {  
  void (*to_fn)(void *);  
  void *to_arg;  
  struct timespec to_wait;  
 };  
   
 pthread_mutexattr_t attr;  
 pthread_mutex_t mutex;  
   
 int makethread(void *(*fn)(void *), void *arg)  
 {  
  int err;  
  pthread_t tid;  
  pthread_attr_t attr;  
   
  err = pthread_attr_init(&attr);  
  if(err != 0)  
   return(err);  
  err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);  
  if(err == 0)  
   err = pthread_create(&tid, &attr, fn, arg);  
  pthread_attr_destroy(&attr);  
  return err;  
 }  
   
 void * timeout_helper(void *arg)  
 {  
  struct to_info *tip;  
  tip = (struct to_info *) arg;  
  nanosleep(&tip->to_wait, NULL);  
  (*tip->to_fn)(tip->to_arg);  
  return 0;  
 }  
   
 void timeout(const struct timespec *period, void (*func)(void*), void *arg)  
 {  
  int err;  
  struct to_info *tip;  
   
  tip = (struct to_info*)malloc(sizeof(struct to_info));  
  tip->to_fn = func;  
  tip->to_arg = arg;  
  tip->to_wait.tv_sec = period->tv_sec;  
  tip->to_wait.tv_nsec = period->tv_nsec;  
  if(tip != NULL) {  
   err = makethread(timeout_helper, (void*)tip);  
   if(err == 0) return;  
  }  
   
  (*func)(arg);  
 }  
   
 void retry(void *arg)  
 {  
  pthread_mutex_lock(&mutex);  
  printf("retry is called!\n");  
  pthread_mutex_unlock(&mutex);  
 }  
   
 int main(void)  
 {  
  int err, condition;  
  long arg;  
  struct timespec period;  
   
  // Initialize the attribute  
  if((err = pthread_mutexattr_init(&attr)) != 0) {  
   printf("pthread_mutexattr_init error!\n");  
   exit(1);  
  }  
   
  if((err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) != 0) {  
   printf("can't do the recursive type!\n");  
   exit(2);  
  }  
   
  if((err = pthread_mutex_init(&mutex, &attr)) != 0) {  
   printf("pthread_mutex_init error!\n");  
   exit(3);  
  }  
   
  // Launch the thread  
  pthread_mutex_lock(&mutex);  
  period.tv_sec = 1;  
  period.tv_nsec = 500;  
  timeout(&period, retry, (void*)arg);  
  pthread_mutex_unlock(&mutex);  
   
  //Wait for 2 seconds to let the thread finish firstly  
  sleep(2);  
  exit(0);  
 }  

shell:
Since before launching the timeout in the main function, it already locked the mutex, and when retry is called, it would lock again. We have to make it recursive mutex to make it work.

 ubuntu@ip-172-31-23-227:~$ ./mutex.out  
 retry is called!  

2. Reader-Writer lock attributes and Condition Variable Attributes
 ubuntu@ip-172-31-23-227:~$ less /usr/include/pthread.h  
 ......  
 /* Initialize attribute object ATTR with default values. */  
 extern int pthread_rwlockattr_init (pthread_rwlockattr_t *__attr)  
    __THROW __nonnull ((1));  
   
 /* Destroy attribute object ATTR. */  
 extern int pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr)  
    __THROW __nonnull ((1));  
   
 /* Return current setting of process-shared attribute of ATTR in PSHARED. */  
 extern int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *  
                      __restrict __attr,  
                      int *__restrict __pshared)  
    __THROW __nonnull ((1, 2));  
   
 /* Set process-shared attribute of ATTR to PSHARED. */  
 extern int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *__attr,  
                      int __pshared)  
    __THROW __nonnull ((1));  
 ......  
 extern int pthread_condattr_init (pthread_condattr_t *__attr)  
    __THROW __nonnull ((1));  
   
 /* Destroy condition variable attribute ATTR. */  
 extern int pthread_condattr_destroy (pthread_condattr_t *__attr)  
    __THROW __nonnull ((1));  
   
 /* Get the process-shared flag of the condition variable attribute ATTR. */  
 extern int pthread_condattr_getpshared (const pthread_condattr_t *  
                     __restrict __attr,  
                     int *__restrict __pshared)  
    __THROW __nonnull ((1, 2));  
   
 /* Set the process-shared flag of the condition variable attribute ATTR. */  
 extern int pthread_condattr_setpshared (pthread_condattr_t *__attr,  
                     int __pshared) __THROW __nonnull ((1));  
 ......  

Similar from mutex attribute.

No comments:

Post a Comment