线程同步

1.互斥量


互斥变量用pthead_mutex_t数据类型来表示,在使用互斥变量之前,必须首先对它进行初始化,可以把它置为常量PTHREAD_MUTEX_INITIALIZER(只对静态分配的互斥量),也可以能过调用pthread_mutex_init函数进行初始化。如果动态地分配互斥量(例如通过调用malloc)函数,那么释放内存前需要使用pthread_mutex_destroy.


int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexarrt_t * restrict arrt);

int pthread_mutex_destroy(pthread_mutex_t &mutex);

返回值:成功返回0,否则返回错误编号。

要用默认的属性初始化互斥量,只需把attr设置为NULL。


int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_trylock(pthread_mutex_t *mutex);

int pthread_mutex_unlock(pthread_mutex_t *mutex);

返回值:成功返回0,否则返回错误编号。



C代码   收藏代码
  1. <span style="background-color: #ffffff; font-size: medium;">#include <stdlib.h>  
  2. #include <pthread.h>  
  3.   
  4. struct foo {  
  5.     int             f_count;  
  6.     pthread_mutex_t f_lock;  
  7.     /* ... more stuff here ... */  
  8. };  
  9.   
  10. struct foo *  
  11. foo_alloc(void/* allocate the object */  
  12. {  
  13.     struct foo *fp;  
  14.   
  15.     if ((fp = malloc(sizeof(struct foo))) != NULL) {  
  16.         fp->f_count = 1;  
  17.         if (pthread_mutex_init(&fp->f_lock, NULL) != 0) {  
  18.             free(fp);  
  19.             return(NULL);  
  20.         }  
  21.         /* ... continue initialization ... */  
  22.     }  
  23.     return(fp);  
  24. }  
  25.   
  26. void  
  27. foo_hold(struct foo *fp) /* add a reference to the object */  
  28. {  
  29.     pthread_mutex_lock(&fp->f_lock);  
  30.     fp->f_count++;  
  31.     pthread_mutex_unlock(&fp->f_lock);  
  32. }  
  33.   
  34. void  
  35. foo_rele(struct foo *fp) /* release a reference to the object */  
  36. {  
  37.     pthread_mutex_lock(&fp->f_lock);  
  38.     if (--fp->f_count == 0) { /* last reference */  
  39.         pthread_mutex_unlock(&fp->f_lock);  
  40.         pthread_mutex_destroy(&fp->f_lock);  
  41.         free(fp);  
  42.     } else {  
  43.         pthread_mutex_unlock(&fp->f_lock);  
  44.     }  
  45. }  
  46. </span>  

 2.避免死锁

如果线程试图对同一个互斥量加锁两次,那么它自身就会陷入死锁状态。

一个线程试图以与另一个线程相反的顺序销售互斥量时,才可能出现死锁。

实例:



C代码   收藏代码
  1. <span style="background-color: #ffffff; font-size: medium;">#include <stdio.h>  
  2.    #include <stdlib.h>  
  3.    #include <unistd.h>  
  4.    #include <pthread.h>  
  5.    #include <errno.h>  
  6.    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  
  7.    int lock_var;  
  8.    time_t end_time;  
  9.    void pthread1(void *arg);  
  10.    void pthread2(void *arg);  
  11.    int main(int argc, char *argv[])  
  12.   {  
  13.     pthread_t id1,id2;  
  14.     pthread_t mon_th_id;  
  15.     int ret;  
  16.     end_time = time(NULL)+10;  
  17.    /*互斥锁初始化*/  
  18.      pthread_mutex_init(&mutex,NULL);  
  19.    /*创建两个线程*/  
  20.      ret=pthread_create(&id1,NULL,(void *)pthread1, NULL);  
  21.      if(ret!=0)  
  22.      perror("pthread cread1");  
  23.      ret=pthread_create(&id2,NULL,(void *)pthread2, NULL);  
  24.      if(ret!=0)  
  25.      perror("pthread cread2");  
  26.      pthread_join(id1,NULL);                                   
  27.      pthread_join(id2,NULL);                                   
  28.      exit(0);                                                  
  29.    }  
  30.                                                             
  31.    void pthread1(void *arg)                                  
  32.    {                                                         
  33.     int i;                                                    
  34.     while(time(NULL) < end_time)  
  35.     {                             
  36.     /*互斥锁上锁*/                                            
  37.      if(pthread_mutex_lock(&mutex)!=0)  
  38.      {                        
  39.       perror("pthread_mutex_lock");                             
  40.      }                                                         
  41.      else                                                      
  42.      printf("pthread1:pthread1 lock the variable\n");          
  43.      for(i=0;i<2;i++){                                         
  44.      sleep(1);                                                 
  45.      lock_var++;                                               
  46.      }                                                         
  47.    /*互斥锁接锁*/                                            
  48.      if(pthread_mutex_unlock(&mutex)!=0){                      
  49.      perror("pthread_mutex_unlock");                           
  50.      }                                                         
  51.      else                                                      
  52.      printf("pthread1:pthread1 unlock the variable\n");        
  53.      sleep(1);                                                 
  54.     }                                                         
  55.    }                                                         
  56.    void pthread2(void *arg)                                  
  57.    {                                                         
  58.     int nolock=0;                                             
  59.     int ret;                                                  
  60.     while(time(NULL) < end_time)  
  61.     {                             
  62.      /*测试互斥锁*/                                            
  63.      ret=pthread_mutex_trylock(&mutex);                        
  64.      if(ret==EBUSY)                                            
  65.      printf("pthread2:the variable is locked by pthread1\n");  
  66.      else  
  67.      {     
  68.       if(ret!=0)  
  69.       {                                                                                         
  70.         perror("pthread_mutex_trylock");                    
  71.         exit(1);                                            
  72.        }                                                   
  73.        else                                                
  74.        printf("pthread2:pthread2 got lock.The variable is%d\n",lock_var);                                    
  75.                /*互斥锁接锁*/                                      
  76.        if(pthread_mutex_unlock(&mutex)!=0)  
  77.        {                
  78.         perror("pthread_mutex_unlock");                     
  79.        }                                                   
  80.        else                                                
  81.        printf("pthread2:pthread2 unlock the variable\n");  
  82.       }                                                   
  83.      sleep(3);                                           
  84.      }                                                   
  85.     } </span>  


 3.读写锁

1)多个读者可以同时进行读
2)写者必须互斥(只允许一个写者写,也不能读者写者同时进行)
3)写者优先于读者(一旦有写者,则后续读者必须等待,唤醒时优先考虑写者)


int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);

初始化读/写锁

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

锁定读/写锁

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

读取读/写锁上的锁

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

写读/写锁上的锁

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

解除读/写锁

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

成功返回0,否则返回错误编号

实例:

 

C代码   收藏代码
  1. <span style="background-color: #ffffff; font-size: medium;">#include <stdlib.h>  
  2. #include <pthread.h>  
  3.   
  4. struct job {  
  5.     struct job *j_next;  
  6.     struct job *j_prev;  
  7.     pthread_t   j_id;   /* tells which thread handles this job */  
  8.     /* ... more stuff here ... */  
  9. };  
  10.   
  11. struct queue {  
  12.     struct job      *q_head;  
  13.     struct job      *q_tail;  
  14.     pthread_rwlock_t q_lock;  
  15. };  
  16.   
  17. /* 
  18.  * Initialize a queue. 
  19.  */  
  20. int  
  21. queue_init(struct queue *qp)  
  22. {  
  23.     int err;  
  24.   
  25.     qp->q_head = NULL;  
  26.     qp->q_tail = NULL;  
  27.     err = pthread_rwlock_init(&qp->q_lock, NULL);  
  28.     if (err != 0)  
  29.         return(err);  
  30.   
  31.     /* ... continue initialization ... */  
  32.   
  33.     return(0);  
  34. }  
  35.   
  36. /* 
  37.  * Insert a job at the head of the queue. 
  38.  */  
  39. void  
  40. job_insert(struct queue *qp, struct job *jp)  
  41. {  
  42.     pthread_rwlock_wrlock(&qp->q_lock);  
  43.     jp->j_next = qp->q_head;  
  44.     jp->j_prev = NULL;  
  45.     if (qp->q_head != NULL)  
  46.         qp->q_head->j_prev = jp;  
  47.     else  
  48.         qp->q_tail = jp; /* list was empty */  
  49.     qp->q_head = jp;  
  50.     pthread_rwlock_unlock(&qp->q_lock);  
  51. }  
  52.   
  53. /* 
  54.  * Append a job on the tail of the queue. 
  55.  */  
  56. void  
  57. job_append(struct queue *qp, struct job *jp)  
  58. {  
  59.     pthread_rwlock_wrlock(&qp->q_lock);  
  60.     jp->j_next = NULL;  
  61.     jp->j_prev = qp->q_tail;  
  62.     if (qp->q_tail != NULL)  
  63.         qp->q_tail->j_next = jp;  
  64.     else  
  65.         qp->q_head = jp; /* list was empty */  
  66.     qp->q_tail = jp;  
  67.     pthread_rwlock_unlock(&qp->q_lock);  
  68. }  
  69.   
  70. /* 
  71.  * Remove the given job from a queue. 
  72.  */  
  73. void  
  74. job_remove(struct queue *qp, struct job *jp)  
  75. {  
  76.     pthread_rwlock_wrlock(&qp->q_lock);  
  77.     if (jp == qp->q_head) {  
  78.         qp->q_head = jp->j_next;  
  79.         if (qp->q_tail == jp)  
  80.             qp->q_tail = NULL;  
  81.     } else if (jp == qp->q_tail) {  
  82.         qp->q_tail = jp->j_prev;  
  83.         if (qp->q_head == jp)  
  84.             qp->q_head = NULL;  
  85.     } else {  
  86.         jp->j_prev->j_next = jp->j_next;  
  87.         jp->j_next->j_prev = jp->j_prev;  
  88.     }  
  89.     pthread_rwlock_unlock(&qp->q_lock);  
  90. }  
  91.   
  92. /* 
  93.  * Find a job for the given thread ID. 
  94.  */  
  95. struct job *  
  96. job_find(struct queue *qp, pthread_t id)  
  97. {  
  98.     struct job *jp;  
  99.   
  100.     if (pthread_rwlock_rdlock(&qp->q_lock) != 0)  
  101.         return(NULL);  
  102.   
  103.     for (jp = qp->q_head; jp != NULL; jp = jp->j_next)  
  104.         if (pthread_equal(jp->j_id, id))  
  105.             break;  
  106.   
  107.     pthread_rwlock_unlock(&qp->q_lock);  
  108.     return(jp);  
  109. }  
  110. </span>  

 

 

这个例子中,不管什么时候需要增加一个作业也不能队列中或者从队列中删除作业,都用写模式锁住队列的读写锁。不管何时搜索队列,首先需要获取读模式下的锁,允许所有的工作线程并发地搜索队列。在这种情况下,只有线程搜索队列的频率远远高于增加或者删除作业时,使用读写锁才可能改善性能。



4.条件变量

 

条件变量是线程可用的另一种同步机制。通常和互斥量一起使用,允许线程以无竞争的方式等待特定条件发生。条件本身由互斥信号量保护,线程在改变条件状态之前必须首先锁住信号量,在获得信号量之前不会察觉到这种改变。

    条件变量在使用之前要初始化。动态分配的可以由pthread_cond_init函数来分配,静态变量可以直接将PTHREAD_COND_INITIALIZER赋给静态分配的条件。动态分配的变量需要使用pthread_mutex_destory来去初始化,然后再free。

静态创建:pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
动态创建:pthread_cond _t cond;
  pthread_cond_init(&cond,NULL);

其中的第二个参数NULL表示条件变量的属性,虽然POSIX中定义了条件变量的属性,但在LinuxThread中并没有实现,因此常常忽略

int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
                      pthread_mutex_t *restrict mutex,
                      const strcut timespec *restrict timeout);
/*若成功则返回真,错误则返回错误编号*/
传递给pthread_cond_wait的互斥量对条件进行保护,调用者把锁住的信号量传给函数,函数把调用线程放到等待条件的线程列表上,然后对互斥量解锁。这个是原子操作,当它返回时,互斥量会被再次锁住。
pthread_cond_timedwait函数的工作方式与pthread_cond_wait函数相似。只是多了一个timeout。timeout变量指定了等待的时间。时间的结构:
struct timespec{
time_t tv_sec; /*seconds*/
long tv_nsec; /*nanoseconds*/
}
int pthread_cond_signal(pthread_cond_t *cond); /*唤醒等待该条件的某个进程*/
int pthread_cond_broadcast(pthread_cond_t *cond); /*唤醒等待该条件的所有进程*/
要注意的是,条件变量只是起阻塞和唤醒线程的作用,具体的判断条件还需用户给出,例如一个变量是否为0等等,这一点我们从后面的例子中可以看到。线程被唤醒后,它将重新检查判断条件是否满足,如果还不满足,一般说来线程应该仍阻塞在这里,被等待被下一次唤醒。这个过程一般用while语句实现。函数pthread_cond_broadcast(pthread_cond_t *cond)用来唤醒所有被阻塞在条件变量cond上的线程。这些线程被唤醒后将再次竞争相应的互斥锁,所以必须小心使用这个函数。

 

实例:

 

C代码   收藏代码
  1. <span style="font-size: medium;">#include<stdio.h>  
  2. #include<pthread.h>  
  3.   
  4. pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;  
  5. pthread_cond_t cond=PTHREAD_COND_INITIALIZER;  
  6. int count=5;  
  7.   
  8. void *decrement(void *arg)  
  9. {  
  10. while(1)  
  11. {  
  12.     pthread_mutex_lock(&mutex);  
  13.     while(count<=0)  
  14.     {  
  15.         printf("count<=0,thread1 is hanging!\n");  
  16.         pthread_cond_wait(&cond,&mutex);  
  17.         sleep(1);  
  18.         printf("sleep!\n");  
  19.     }  
  20.     count=count-1;  
  21.     pthread_mutex_unlock(&mutex);      
  22.   
  23.     if(count==9)  
  24.     {  
  25.         printf("count=9,thread1 is over!\n");  
  26.         return NULL;  
  27.     }  
  28. }  
  29.   
  30. }  
  31.   
  32. void *increment(void *arg)  
  33. {sleep(1);  
  34. while(1)  
  35. {  
  36.     pthread_mutex_lock(&mutex);  
  37.     count=count+1;  
  38.     if(count>0)  
  39.     {  
  40.         printf("count=%d,change cond state!\n",count);  
  41.         pthread_cond_signal(&cond);  
  42.     }  
  43.     pthread_mutex_unlock(&mutex);  
  44.   
  45.     if(count==10)  
  46.     {  
  47.         printf("count=10,thread2 is over!\n");  
  48.         return NULL;  
  49.     }  
  50. }  
  51.   
  52. }  
  53.   
  54. int main()  
  55. {  
  56.     int i1=1,i2=1;  
  57.     pthread_t id1,id2;  
  58.     pthread_mutex_init(&mutex,NULL);  
  59.     pthread_cond_init(&cond,NULL);  
  60.     pthread_create(&id1,NULL,decrement,NULL);  
  61.     pthread_create(&id2,NULL,increment,NULL);  
  62.       
  63.     i2=pthread_join(id2,NULL);  
  64.     i1=pthread_join(id1,NULL);  
  65.     if((i2==0)&&(i1==0))  
  66.     {  
  67.         printf("count=%d,the main thread!\n",count);  
  68.         pthread_cond_destroy(&cond);  
  69.         pthread_mutex_destroy(&mutex);  
  70.         return 0;  
  71.     }  
  72. }</span>  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值