Linux多线程,线程同步(2)

5 篇文章 0 订阅
5 篇文章 0 订阅

2)条件变量(cond

    利用线程间共享的全局变量进行同步的一种机制。条件变量上的基本操作有:触发条件(当条件变为 true );等待条件,挂起线程直到其他线程触发条件。

int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr);   

int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);

int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);

int pthread_cond_destroy(pthread_cond_t *cond);

int pthread_cond_signal(pthread_cond_t *cond);

int pthread_cond_broadcast(pthread_cond_t *cond);  //解除所有线程的阻塞

(1)初始化.init()或者pthread_cond_t cond=PTHREAD_COND_INITIALIER(前者为动态初始化,后者为静态初始化);属性置为NULL

(2)等待条件成立.pthread_wait,pthread_timewait.wait()释放锁,并阻塞等待条件变量为真,timewait()设置等待时间,仍未signal,返回ETIMEOUT(加锁保证只有一个线程wait)

(3)激活条件变量:pthread_cond_signal,pthread_cond_broadcast(激活所有等待线程)

(4)清除条件变量:destroy;无线程等待,否则返回EBUSY

对于

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);

int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);

一定要在mutex的锁定区域内使用

    如果要正确的使用pthread_mutex_lockpthread_mutex_unlock,请参考

pthread_cleanup_push和pthread_cleanup_pop宏,它能够在线程被cancel的时候正确的释放mutex

    另外,posix1标准说,pthread_cond_signalpthread_cond_broadcast无需考虑调用线程是否是mutex的拥有者,也就是说,可以在lockunlock以外的区域调用。如果我们对调用行为不关心,那么请在lock区域之外调用吧。

说明:

    (1)pthread_cond_wait 自动解锁互斥量(如同执行了pthread_unlock_mutex),并等待条件变量触发。这时线程挂起,不占用CPU时间,直到条件变量被触发(变量为ture)。在调用 pthread_cond_wait之前,应用程序必须加锁互斥量。pthread_cond_wait函数返回前,自动重新对互斥量加锁(如同执行了pthread_lock_mutex)

    (2)互斥量的解锁和在条件变量上挂起都是自动进行的。因此,在条件变量被触发前,如果所有的线程都要对互斥量加锁,这种机制可保证在线程加锁互斥量和进入等待条件变量期间,条件变量不被触发。条件变量要和互斥量相联结,以避免出现条件竞争——个线程预备等待一个条件变量,当它在真正进入等待之前,另一个线程恰好触发了该条件(条件满足信号有可能在测试条件和调用pthread_cond_wait函数(block)之间被发出,从而造成无限制的等待)。

(3)pthread_cond_timedwait 和 pthread_cond_wait 一样,自动解锁互斥量及等待条件变量,但它还限定了等待时间。如果在abstime指定的时间内cond未触发,互斥量mutex被重新加锁,且pthread_cond_timedwait返回错误 ETIMEDOUTabstime 参数指定一个绝对时间,时间原点与 time 和 gettimeofday 相同:abstime = 0 表示19701100:00:00 GMT

(4)pthread_cond_destroy 销毁一个条件变量,释放它拥有的资源。进入 pthread_cond_destroy 之前,必须没有在该条件变量上等待的线程。

    (5)条件变量函数不是异步信号安全的,不应当在信号处理程序中进行调用。特别要注意,如果在信号处理程序中调用 pthread_cond_signal 或 pthread_cond_boardcast函数,可能导致调用线程死锁。

示例程序1

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <pthread.h>  
  3. #include "stdlib.h"  
  4. #include "unistd.h"  
  5.   
  6.   
  7. pthread_mutex_t mutex;  
  8. pthread_cond_t cond;  
  9.   
  10.   
  11. void hander(void *arg)  
  12. {  
  13.     free(arg);  
  14.     (void)pthread_mutex_unlock(&mutex);  
  15. }  
  16.   
  17.   
  18. void *thread1(void *arg)  
  19. {  
  20.      pthread_cleanup_push(hander, &mutex);  
  21.      while(1)  
  22.      {  
  23.          printf("thread1 is running\n");  
  24.          pthread_mutex_lock(&mutex);  
  25.          pthread_cond_wait(&cond,&mutex);  
  26.          printf("thread1 applied the condition\n");  
  27.          pthread_mutex_unlock(&mutex);  
  28.          sleep(4);  
  29.      }  
  30.      pthread_cleanup_pop(0);  
  31.  }  
  32.    
  33. void *thread2(void *arg)  
  34. {  
  35.      while(1)  
  36.      {  
  37.          printf("thread2 is running\n");  
  38.          pthread_mutex_lock(&mutex);  
  39.          pthread_cond_wait(&cond,&mutex);  
  40.          printf("thread2 applied the condition\n");  
  41.          pthread_mutex_unlock(&mutex);  
  42.          sleep(1);  
  43.      }  
  44. }  
  45. int main()  
  46. {  
  47.      pthread_t thid1,thid2;  
  48.      printf("condition variable study!\n");  
  49.      pthread_mutex_init(&mutex,NULL);  
  50.      pthread_cond_init(&cond,NULL);  
  51.      pthread_create(&thid1,NULL,thread1,NULL);  
  52.      pthread_create(&thid2,NULL,thread2,NULL);  
  53.      sleep(1);  
  54.      do  
  55.      {  
  56.          pthread_cond_signal(&cond);  
  57.      }while(1);  
  58.      sleep(20);  
  59.      pthread_exit(0);  
  60.     return 0;  
  61. }  
示例2
[cpp]  view plain copy
  1.    
  2.   
  3. #include <pthread.h>   
  4. #include <unistd.h>   
  5. #include "stdio.h"  
  6. #include "stdlib.h"  
  7.   
  8.   
  9. static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;   
  10. static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;   
  11.   
  12. struct node   
  13. {   
  14.     int n_number;   
  15.     struct node *n_next;   
  16. } *head = NULL;   
  17.   
  18. /*[thread_func]*/   
  19. static void cleanup_handler(void *arg)   
  20. {   
  21.     printf("Cleanup handler of second thread./n");   
  22.     free(arg);   
  23.     (void)pthread_mutex_unlock(&mtx);   
  24. }   
  25.   
  26. static void *thread_func(void *arg)   
  27. {   
  28.     struct node *p = NULL;   
  29.   
  30.     pthread_cleanup_push(cleanup_handler, p);   
  31.     while (1)   
  32.     {   
  33.          //这个mutex主要是用来保证pthread_cond_wait的并发性  
  34.         pthread_mutex_lock(&mtx);            
  35.         while (head == NULL)     
  36.         {                 
  37.             //这个while要特别说明一下,单个pthread_cond_wait功能很完善,为何  
  38.             //这里要有一个while (head == NULL)呢?因为pthread_cond_wait里的线  
  39.             //程可能会被意外唤醒,如果这个时候head != NULL,则不是我们想要的情况。  
  40.             //这个时候,应该让线程继续进入pthread_cond_wait  
  41.               
  42.             // pthread_cond_wait会先解除之前的pthread_mutex_lock锁定的mtx,  
  43.             //然后阻塞在等待对列里休眠,直到再次被唤醒(大多数情况下是等待的条件成立  
  44.             //而被唤醒,唤醒后,该进程会先锁定先pthread_mutex_lock(&mtx);,再读取资源  
  45.             //用这个流程是比较清楚的/*block-->unlock-->wait() return-->lock*/  
  46.             pthread_cond_wait(&cond, &mtx);           
  47.             p = head;   
  48.             head = head->n_next;   
  49.             printf("Got %d from front of queue/n", p->n_number);   
  50.             free(p);   
  51.         }  
  52.         pthread_mutex_unlock(&mtx);             //临界区数据操作完毕,释放互斥锁  
  53.     }   
  54.     pthread_cleanup_pop(0);   
  55.     return 0;   
  56. }   
  57.   
  58. int main(void)   
  59. {   
  60.     pthread_t tid;   
  61.     int i;   
  62.     struct node *p;   
  63.     //子线程会一直等待资源,类似生产者和消费者,但是这里的消费者可以是多个消费者,而  
  64.     //不仅仅支持普通的单个消费者,这个模型虽然简单,但是很强大  
  65.     pthread_create(&tid, NULL, thread_func, NULL);     
  66.     sleep(1);  
  67.     for (i = 0; i < 10; i++)   
  68.     {   
  69.         p = (struct node*)malloc(sizeof(struct node));   
  70.         p->n_number = i;   
  71.         pthread_mutex_lock(&mtx);             //需要操作head这个临界资源,先加锁,  
  72.         p->n_next = head;   
  73.         head = p;   
  74.         pthread_cond_signal(&cond);   
  75.         pthread_mutex_unlock(&mtx);           //解锁  
  76.         sleep(1);   
  77.     }   
  78.     printf("thread 1 wanna end the line.So cancel thread 2./n");   
  79.       
  80.     //关于pthread_cancel,有一点额外的说明,它是从外部终止子线程,子线程会在最近的取消点,退出  
  81.     //线程,而在我们的代码里,最近的取消点肯定就是pthread_cond_wait()了。  
  82.     pthread_cancel(tid);              
  83.     pthread_join(tid, NULL);   
  84.     printf("All done -- exiting/n");   
  85.     return 0;   
  86. }  

3)信号量

    如同进程一样,线程也可以通过信号量来实现通信,虽然是轻量级的。

    信号量函数的名字都以"sem_"打头。线程使用的基本信号量函数有四个。

#include <semaphore.h>

int sem_init (sem_t *sem , int pshared, unsigned int value);

    这是对由sem指定的信号量进行初始化,设置好它的共享选项(linux 只支持为0,即表示它是当前进程的局部信号量),然后给它一个初始值VALUE

两个原子操作函数:

int sem_wait(sem_t *sem);

int sem_post(sem_t *sem);

    这两个函数都要用一个由sem_init调用初始化的信号量对象的指针做参数。

sem_post:给信号量的值加1

sem_wait:给信号量减1;对一个值为0的信号量调用sem_wait,这个函数将会等待直到有其它线程使它不再是0为止。

int sem_destroy(sem_t *sem);

    这个函数的作用是再我们用完信号量后都它进行清理。归还自己占有的一切资源。

参考:

1】 http://www.cnblogs.com/feisky/archive/2009/11/12/1601824.html

2】 http://www.cnblogs.com/mydomain/archive/2011/07/10/2102147.html

3】 线程函数介绍

http://www.unix.org/version2/whatsnew/threadsref.html

4】 http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html

5】 线程常用函数简介

http://www.rosoo.net/a/201004/8954.html

6】 条件变量

http://blog.csdn.net/hiflower/article/details/2195350

7】条件变量函数说明

http://blog.csdn.net/hairetz/article/details/4535920

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值