概述

  • 等待条件变量总是返回锁住的互斥量。
  • 条件变量的作用是发送信号,而不是互斥。
  • 与条件变量相关的共享数据是“谓词”,如队列满或队列空条件。
  • 一个条件变量应该与一个谓词相关。如果一个条件变量与多个谓词相关,或者多个条件变量与一个谓词相关,有可能死锁。

主线程(Main Thread

  1. 声明和初始化需要同步的全局数据/变量(如“count”)
  2. 生命和初始化一个条件变量对象
  3. 声明和初始化一个相关的互斥量
  4. 创建工作线程A和B

Thread A

  • 工作,一直到一定的条件满足(如“count”等于一个指定的值)
  • 锁定相关互斥量并检查全局变量的值
  • 调用pthread_cond_wait()阻塞等待Thread-B的信号。注意pthread_cond_wait()能够自动地并且原子地解锁相关的互斥量,以至于它可以被Thread-B使用。
  • 当收到信号,唤醒线程,互斥量被自动,原子地锁定。
  • 显式解锁互斥量
  • 继续

Thread B

  • 工作
  • 锁定相关互斥量
  • 改变Thread-A所等待的全局变量
  • 检查全局变量的值,若达到需要的条件,像Thread-A发信号。
  • 解锁互斥量
  • 继续

创建和销毁条件变量

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int pthread_cond_init (pthread_cond_t *cond, pthread_condattr_t *condattr);
int pthread_cond_destroy(pthread_cond_t *cond);
  • 永远不要copy一个条件变量,因为使用条件变量的备份是不可知的。不过,可以传递条件变量的指针以使不同函数和线程可以使用它来同步。
  • 为了获得最好的结果,应该将条件变量与相关的谓词“链接”在一起。
 
静态初始化条件变量:
 #include<pthread.h>
#include "errors.h" typedef struct my_struct_tag {
pthread_mutex_t mutex;
pthread_cond_t cond;
int value;
} my_struct_t; my_struct_t data = {
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_COND_INITIALIZER, }; int main(int argc, char* argv[])
{
return ;
}

cond_static.c

动态初始化条件变量:
 #include<pthread.h>
#include "errors.h" typedef struct my_struct_tag {
pthread_mutex_t mutex;
pthread_cond_t cond;
int value;
} my_struct_t; int main(int argc, char* argv[])
{
my_struct_t *data;
int status; data = malloc(sizeof(my_struct_t));
if ( data ==NULL ) {
errno_abort("malloc");
} /*
* init
*/
status = pthread_mutex_init(&data->mutex, NULL);
if ( status != ) {
err_abort(status, "mutex init");
}
status = pthread_cond_init(&data->cond);
if ( status != ) {
err_abort(status, "cond init");
} /*
* destroy
*/
status = pthread_cond_destroy(&data->mutex);
if ( status != ) {
err_abort(status, "destroy cond");
} status = pthread_mutex_destroy(&data->mutex);
if ( status != ) {
err_abort(status, "destroy mutex");
}
free(data);
return status;
}

cond_dynamic.c

等待条件变量

  • 在阻塞线程之前,条件变量等待操作将解锁互斥量;而在重新返回线程之前,将再次锁住互斥量。
  • 所有并发等待同一个条件变量的线程必须指定同一个相关互斥量。
  • 任何条件变量在特定时刻只能与一个互斥量相关联,而互斥量则可以同时与多个条件变量关联。
  • 在锁住相关的互斥量之后和在等待条件变量之前,测试谓词是很重要的。
int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex);
int pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, struct timespec* expiration)
 #include<time.h>
#include<pthread.h>
#include "errors.h" typedef struct my_struct_tag {
pthread_cond_t cond;
pthread_mutex_t mutex;
int value;
} my_struct_t; my_struct_t data = {
PTHREAD_COND_INITIALIZER,
PTHREAD_MUTEX_INITIALIZER, }; int hibernation = ; void* wait_thread(void* arg)
{
int status;
sleep(hibernation);
status = pthread_mutex_lock(&data.mutex);
if (status != )
err_abort(status, "Lock mutex");
data.value = ;
status = pthread_cond_signal(&data.cond);
if (status != )
err_abort(status, "Signal condition");
status = pthread_mutex_unlock(&data.mutex);;
if (status != )
err_abort(status, "Unlock mutex");
return NULL;
} int main(int argc, char* argv[])
{
int status;
pthread_t wait_thread_id;
struct timespec timeout; if (argc > )
hibernation = atoi(argv[]); status = pthread_create(&wait_thread_id, NULL, wait_thread, NULL);
if (status != )
err_abort(status, "Create wait thread"); timeout.tv_sec = time(NULL) + ;
timeout.tv_nsec = ; status = pthread_mutex_lock(&data.mutex);
if (status != )
err_abort(status, "Lock mutex"); while(data.value == ) {
status = pthread_cond_timedwait(&data.cond, &data.mutex, &timeout);
if (status == ETIMEDOUT) {
printf("Condition wait timed out.\n");
break;
}
else if (status != )
err_abort(status, "wait on condition");
}
if (data.value != )
printf("Condition was signaled.\n");
status = pthread_mutex_unlock(&data.mutex);
if (status != )
err_abort(status, "Unlock mutex");
return ;
}

cond.c

 

唤醒条件变量等待线程

int pthread_cond_signal(pthread_cond_t* cond);
int pthread_cond_broadcast(pthread_cond_t* cond);
  • pthread_cond_wait()阻塞调用线程直到指定的条件受信(signaled)。该函数应该在互斥量锁定时调用,当在等待时会自动解锁互斥量。在信号被发送,线程被激活后,互斥量会自动被锁定,当线程结束时,由程序员负责解锁互斥量。
  • pthread_cond_signal()函数用于向其他等待在条件变量上的线程发送信号(激活其它线程)。应该在互斥量被锁定后调用。
  • 若不止一个线程阻塞在条件变量上,则应用pthread_cond_broadcast()向其它所以线程发生信号。
  • 在调用pthread_cond_wait()前调用pthread_cond_signal()会发生逻辑错误。
  • 使用这些函数时适当的锁定和解锁相关的互斥量是非常重要的。如:
    1. 调用pthread_cond_wait()前锁定互斥量失败可能导致线程不会阻塞。
    2. 调用pthread_cond_signal()后解锁互斥量失败可能会不允许相应的pthread_cond_wait()函数结束(保存阻塞)。

Alarm最终版本

 #include<pthread.h>
#include<time.h>
#include"errors.h" typedef struct alarm_tag {
struct alarm_tag *link;
int seconds;
time_t time;
char message[];
} alarm_t; pthread_mutex_t alarm_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t alarm_cond = PTHREAD_COND_INITIALIZER;
alarm_t* alarm_list = NULL;
time_t current_alarm = ; /*
* insert alarm entry on list, in order.
*/
void alarm_insert(alarm_t* alarm)
{
int status;
alarm_t **last, *next; /*
* this routine requires that the caller have locker the alarm_mutex.
*/
last = &alarm_list;
next = *last;
next = *last;
while (next != NULL) {
if (next->time >= alarm->time) {
alarm->link = next;
*last = alarm;
break;
}
last = &next->link;
next = next->link;
}
if (next == NULL) {
*last = alarm;
alarm->link = NULL;
}
#ifdef DEBUG
printf("[list: ");
for (next = alarm_list; next != NULL; next = next->link)
printf("%d(%d)[\"%s\"]", next->time, next->time - time(NULL), next->message);
printf("]\n");
#endif
/*
* wake the alarm thread if it is not busy(
* that is, if current alarm is 0, signifying that it's waiting for work),
* or if the new alarm comes before the one on which the alarm thread is waiting.
*/
if (current_alarm == || alarm->time < current_alarm) {
current_alarm = alarm->time;
status = pthread_cond_signal(&alarm_cond);
if (status != )
err_abort(status, "Signal cond");
}
} void *alarm_thread(void* arg)
{
alarm_t* alarm;
struct timespec cond_time;
time_t now;
int status, expired; /*
* loop forever, processing commands.
* the alarm thread will be disintegrated when the process exits.
* lock the mutex at the start -- it while be unlocked during condi
* -tion waits, so the main thread can insert alarms.
*/
status = pthread_mutex_lock(&alarm_mutex);
if (status != )
err_abort(status, "Lock mutex");
while () {
/*
* if the alarm list is enpty, wait until an alarm is added.
* setting current_alarm to 0 informs the insert routine that
* the trhead is not busy.
*/
current_alarm = ;
while (alarm_list == NULL) {
status = pthread_cond_wait(&alarm_cond, &alarm_mutex);
if (status != )
err_abort(status, "wait on cond");
}
alarm = alarm_list;
alarm_list = alarm->link;
now = time(NULL);
expired = ;
if (alarm->time > now) {
#ifdef DEBUG
printf("[waiting: %d(%d)\"%s\"]\n",alarm->time,
alarm->time - time(NULL), alarm->message);
#endif
cond_time.tv_sec = alarm->time;
cond_time.tv_nsec = ;
current_alarm = alarm->time;
while (current_alarm == alarm->time) {
status = pthread_cond_timedwait(
&alarm_cond, &alarm_mutex, &cond_time);
if (status == ETIMEDOUT) {
expired = ;
break;
}
if (status != )
err_abort(status, "cond timedwait");
}
if (!expired)
alarm_insert(alarm);
}
else
expired = ;
if (expired) {
printf("(%d) %s\n", alarm->seconds, alarm->message);
free(alarm);
}
} } int main(int argc, char* argv[])
{
int status;
char line[];
alarm_t *alarm;
pthread_t thread; status = pthread_create(
&thread, NULL, alarm_thread, NULL);
if (status != )
err_abort(status, "create alarm thread");
while () {
printf("Alarm> ");
if (fgets(line, sizeof(line), stdin) == NULL) exit();
if (strlen(line) <= ) continue;
alarm = (alarm_t*)malloc(sizeof(alarm_t));
if (alarm == NULL)
errno_abort("Allocate alarm"); if (sscanf(line, "%d %64[^\n]", &alarm->seconds, alarm->message) < ) {
fprintf(stderr, "Bad command\n");
free(alarm);
} else {
status = pthread_mutex_lock(&alarm_mutex);
if (status != )
err_abort(status, "Lock mutex");
alarm->time = time(NULL) + alarm->seconds; alarm_insert(alarm);
status = pthread_mutex_unlock(&alarm_mutex);
if (status != )
err_abort(status, "Unlock mutex");
}
}
}

alarm_cond.c

posix thread条件变量的更多相关文章

  1. Linux Qt使用POSIX多线程条件变量、互斥锁(量)

    今天团建,但是文章也要写.酒要喝好,文要写美,方为我辈程序员的全才之路.嘎嘎 之前一直在看POSIX的多线程编程,上个周末结合自己的理解,写了一个基于Qt的用条件变量同步线程的例子.故此来和大家一起分 ...

  2. posix多线程--条件变量

    条件变量是用来通知共享数据状态信息的. 1.条件变量初始化两种方式:(1)静态初始化pthread_cond_t cond = PTHREAD_COND_INITIALIZER;代码示例如下: #in ...

  3. Linux Posix线程条件变量

    生产者消费者模型 .多个线程操作全局变量n,需要做成临界区(要加锁--线程锁或者信号量) .调用函数pthread_cond_wait(&g_cond,&g_mutex)让这个线程锁在 ...

  4. 并发编程(一): POSIX 使用互斥量和条件变量实现生产者/消费者问题

    boost的mutex,condition_variable非常好用.但是在Linux上,boost实际上做的是对pthread_mutex_t和pthread_cond_t的一系列的封装.因此通过对 ...

  5. Linux多线程实践(8) --Posix条件变量解决生产者消费者问题

    Posix条件变量 int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr); int pthread_co ...

  6. posix 条件变量与互斥锁 示例生产者--消费者问题

    一.posix 条件变量 一种线程间同步的情形:线程A需要等某个条件成立才能继续往下执行,现在这个条件不成立,线程A就阻塞等待,而线程B在执行过程中使这个条件成立了,就唤醒线程A继续执行. 在pthr ...

  7. POSIX 使用互斥量和条件变量实现生产者/消费者问题

    boost的mutex,condition_variable非常好用.但是在Linux上,boost实际上做的是对pthread_mutex_t 和pthread_cond_t的一系列的封装.因此通过 ...

  8. 并发编程入门(一): POSIX 使用互斥量和条件变量实现生产者/消费者问题

    boost的mutex,condition_variable非常好用.但是在Linux上,boost实际上做的是对pthread_mutex_t和pthread_cond_t的一系列的封装.因此通过对 ...

  9. linux Posix线程同步(条件变量) 实例

    条件变量:与互斥量一起使用,暂时申请不到某资源时进入条件阻塞等待,当资源具备时线程恢复运行 应用场合:生产线程不断的生产资源,并通知产生资源的条件,消费线程在没有资源情况下进入条件等待,一直等到条件信 ...

随机推荐

  1. HDU5593 ZYB's Tree 树形DP +分治

    感觉其实就是树分治,一次BC的题,感觉这次题目质量比较高,仅代表蒟蒻的看法 一次DFS获取每个点到子树的距离不大于K的点的个数, 然后一遍BFS获取从每个点父亲不大于K的的个数,层层扩展,还是想说 其 ...

  2. selenium在chrome上运行报 Element is not clickable at point (1096, 26)

    Firefox上正常运行的脚本在chrome上提示Element is not clickable at point (1096, 26).分析原因,首先肯定不是因为页面元素不存在而无法点击.也不是要 ...

  3. 【原创】_INTSIZEOF 内存按照int对齐

    #include <stdarg.h> 里面定义了如下宏 #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(siz ...

  4. Java中使用ThreadPoolExecutor并行执行独立的单线程任务

    Java SE 5.0中引入了任务执行框架,这是简化多线程程序设计开发的一大进步.使用这个框架可以方便地管理任务:管理任务的生命周期以及执行策略. 在这篇文章中,我们通过一个简单的例子来展现这个框架所 ...

  5. Eclipse的DDMS File Explorer无法进入data目录解决方案

    进入data目录需要root权限.所以,你的手机要有root才可以.然后做以下步骤就可以了 1.cmd进入platform-tools目录 2.adb shell 3.su(这里要看手机有没有请求ro ...

  6. mssql游标demo

    declare @billIds varchar(400) declare @billId varchar(40) DECLARE c1 CURSOR FOR select top 5 SaleNo ...

  7. Asp.Net底层解析

    写的很好的一篇文章,但由于不能转载 所以把链接发在这里,以方便自己以后看 http://blog.csdn.net/mlcactus/article/details/8564347 http://ji ...

  8. 继承BaseAdapter实现Filterable的adapter类完整示例

    转载:http://www.lai18.com/content/1631130.html 目标:自定义ListView项布局通常需要自己实现Adapter,并通过搜索关键字筛选部分数据.且关键字变长变 ...

  9. DOS/Windows下黑客攻防(一)——神秘黑客大曝光

    一.认识神秘的黑客 谈到网络安全,人们不自觉间就会联想到黑客,人们往往会将他们同破坏网络安全.盗取用户账号.偷窃个人私密信息联系起来.其实黑客也有好坏之分,他们并不全是网络上的捣乱分子,其中也有一部分 ...

  10. Swift基本语法以及与OC的比较

    一.注释: 1.单行注释和OC一致. 2.块注释中有与OC不同点:可以嵌套注释 二.常量和变量: 1.常量:初始化后可读不可写 let 2.变量:初始化后可读可写 var //不需要指定类型,系统会自 ...