pthread条件变量等待条件有两种方式:无条件等待pthread_cond_wait()和计时等待pthread_cond_timedwait(),其中计时等待方式如果在给定时刻前条件没有满足,则返回ETIMEOUT,结束等待,其中abstime以与time()系统调用相同意义的绝对时间形式出现,0表示格林尼治时间1970年1月1日0时0分0秒。  
   
 无论哪种等待方式,都必须和一个互斥锁配合,以防止多个线程同时请求pthread_cond_wait()(或pthread_cond_timedwait())的竞争条件。mutex互斥锁必须是普通锁(PTHREAD_MUTEX_TIMED_NP)或者适应锁(PTHREAD_MUTEX_ADAPTIVE_NP),且在调用pthread_cond_wait()前必须由本线程加锁(pthread_mutex_lock()),而在更新条件等待队列以前,mutex保持锁定状态,并在线程挂起进入等待前解锁。在条件满足从而离开pthread_cond_wait()之前,mutex将被重新加锁,以与进入pthread_cond_wait()前的加锁动作对应。

 #include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h> static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; struct node {
int n_number;
struct node *n_next;
} *head = NULL; // 线程清理函数
static void cleanup_handler(void *arg)
{
printf("Cleanup handler of second thread.\n");
free(arg);
(void)pthread_mutex_unlock(&mtx);
} static void *thread_func(void *arg)
{
struct node *p = NULL; pthread_cleanup_push(cleanup_handler, p);
while (true) {
//这个mutex主要是用来保证pthread_cond_wait的并发性
pthread_mutex_lock(&mtx); /*
因为pthread_cond_wait里的线程可能会被意外唤醒,
如果这个时候head != NULL,则不是我们想要的情况。
这个时候,应该让线程继续进入pthread_cond_wait
*/
while (head == NULL) {
/*
pthread_cond_wait会先解除之前的pthread_mutex_lock锁定的mtx,
然后阻塞在等待对列里休眠,直到再次被唤醒(大多数情况下是等待的条件成立而被唤醒,
唤醒后,该进程会先锁定先pthread_mutex_lock(&mtx);再读取资源
用这个流程是比较清楚的block-->unlock-->wait() return-->lock
*/
pthread_cond_wait(&cond, &mtx);
}
p = head;
head = head->n_next;
printf("Got %d from front of queue\n", p->n_number);
free(p);
//临界区数据操作完毕,释放互斥锁
pthread_mutex_unlock(&mtx);
}
pthread_cleanup_pop();
return ;
} int main(void)
{
pthread_t tid;
int i;
struct node *p;
pthread_create(&tid, NULL, thread_func, NULL); for (i = ; i < ; i++) {
p = (struct node*)malloc(sizeof(struct node));
p->n_number = i; // 加锁->signal->解锁
pthread_mutex_lock(&mtx);
p->n_next = head;
head = p;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mtx);
sleep();
}
printf("cancel thread\n");
/*
从外部终止子线程,子线程会在最近的取消点,退出线程
最近的取消点肯定就是pthread_cond_wait()了。
*/
pthread_cancel(tid);
// 等待cancel完成,不然可能不会执行到cleanup。
pthread_join(tid, NULL);
printf("All done -- exiting\n");
return ;
}

pthread_cleanup_push来注册清理函数rtn,这个函数有一个参数arg。在以下三种情形之一发生时,注册的清理函数被执行:
    1)调用pthread_exit。
    2)作为对取消线程请求(pthread_cancel)的响应。
    3)以非0参数调用pthread_cleanup_pop。
注意:
    1)如果线程只是由于简单的返回而终止的,则清除函数不会被调用。
    2)如果pthread_cleanup_pop被传递0参数,则清除函数不会被调用,但是会清除处于栈顶的清理函数。

最新文章

  1. DateSort选择法、冒泡法排序
  2. 分页查询:使用分页类查询 用get传值
  3. 如何实现一个c/s模式的flv视频点播系统
  4. 单列模式 (singleton pattern)
  5. amcharts报表制作
  6. mysql源码安装(5.1)
  7. a:hover span 隐藏/显示 问题
  8. droppable的详细参数讲解
  9. CentOS6.3下安装配置SVN(Subversion)
  10. react构建淘票票webapp,及react与vue的简单比较。
  11. LeetCode 53. Maximum Subarray(最大的子数组)
  12. vue动态添加路由addRoutes之不能将动态路由存入缓存
  13. Javascript 对象 - 数学对象
  14. dubbo实现原理之SPI简介
  15. 为什么重写equals还要重写hashcode??
  16. MySQL主从复制部署
  17. python之路----socketserver模块
  18. springboot项目的搭建
  19. 为什么说Java String 类型的值是不可改变的?
  20. 2018.11.8 Error contacting service. It is probably not running.

热门文章

  1. [洛谷P3521][POI2011]ROT-Tree Rotations
  2. Visual Studio调试之断点技巧篇补遗
  3. nm用法小记
  4. Win10的WSL很好用呀
  5. POJ2912:Rochambeau(带权并查集)
  6. AngularJs开发——控制器间的通信
  7. python单例与数据库连接池
  8. border-1px;避免移动端下边框部分2px
  9. Java之戳中痛点 - (1)易变业务使用脚本语言编写
  10. 记录一次Nginx跳转报错的问题