在linux多线程编程中,线程的执行顺序是不可预知的,但是有时候由于某些需求,需要多个线程在启动时按照一定的顺序执行,虽然可以使用一些比较简陋的做法,例如:如果有3个线程 ABC,要求执行顺序是A-->B-->C,可以create A--->sleep---->create B---->sleep--->create C,但是这未免有点不靠谱,浪费时间不说,如果要求更多,比如要A线程跑起来并且初始化一些条件后,BC才陆续执行,怎么办呢?看到APUE的条件变量这才找到了一个合适的方法。

  条件变量需要于互斥锁结合使用,条件变量的类型是pthread_cond_t,由于条件变量是用在多线程里的,每个线程都可以看到这个变量,通常就把它定义为全局变量。操作条件变量的函数有:

  •   初始化和销毁
SYNOPSIS
#include <pthread.h> int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);  //动态初始化方法,使用完用用destroy释放资源
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//静态初始化
  •   条件等待
       int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex)

  pthread_cond_timedwait是带超时的等待函数,如果时间到了条件依然没变则返回超时错误,参数里面的mutex就是与之配合使用的互斥量。

  •   条件通知
       int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);

使用的方法:

  这里假定有2个线程,一个等待条件满足,一个改变条件并发出条件改变的通知。等待的线程:

      while (  )
{
pthread_mutex_lock(&mtx);
while ( 条件 == FALSE )
{
pthread_cond_wait(&cond, &mtx);
}
   将条件改变为FALSE
pthread_mutex_unlock(&mtx);
}

  改变条件并通知的线程:

         pthread_mutex_lock(&mtx);
条件 = TRUE;
pthread_mutex_unlock(&mtx);
pthread_cond_signal(&cond);

  需要注意这里代码里的 '条件' 和条件变量 cond是2码事,cond只是用作在线程间传递 '条件' 改变了的一个信使。

  先看看2个模块的流程:

在pthread_cond_wait函数中,进去前会unlock mtx,等待返回时又会lock mtx。

  分析一下2个线程按随机顺序执行时会怎么样,左边线程叫 A,右边线程叫B,假设 A先lock,这时B就阻塞了,然后A改变条件,解锁,发出通知,由于A接了锁,B马上唤醒,获得锁,那么这时A是无法改变条件的,因为锁被B获得了,B解锁,然后等待,收到通知,B在等待条件队列里面被唤醒,加锁,(这个wait过程按道理要做成原子操作才行,我个人觉得,不然进入wait前的unlock可能又会被A线程抢了锁),B处理完一些事后,解锁,然后不管是A还是B再次获得锁,A都会在解锁后发出通知,B都会在进入等待前解开锁,处理时又锁住,处理完又解锁,也就是说条件变量在需要传递时的通道是被打开的,改变条件变量的过程中又是被封住的。

 #include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.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; void *cleanup(void *arg)
{
printf("p:%p\n",arg);
printf("clean up\n");
} void *threadfun(void *arg)
{
struct node *p; pthread_cleanup_push(cleanup, NULL);
while ( )
{
pthread_mutex_lock(&mtx);
while ( head == NULL )
{
pthread_cond_wait(&cond, &mtx);
}
p = head;
head = head->n_next;
pthread_mutex_unlock(&mtx); printf("thread node number is:%d\n",p->n_number);
free(p);
}
pthread_cleanup_pop();
return (void *);
} int main(void)
{
int ret, i;
pthread_t tid;
struct node *p; ret = pthread_create(&tid, NULL, threadfun, NULL);
if ( ret != )
{
perror("pthread_create error\n");
return -;
} for ( i = ; i < ; i++ )
{
p = (struct node *)malloc(sizeof(struct node));
if ( p == NULL )
{
perror("malloc error\n");
continue;
}
memset(p, 0x0, sizeof(struct node));
p->n_number = i;
pthread_mutex_lock(&mtx);
p->n_next = head;
head = p;
pthread_mutex_unlock(&mtx);
pthread_cond_signal(&cond);
sleep();
} ret = pthread_cancel(tid);
if ( ret != )
{
printf("pthread_cancel error\n");
} ret = pthread_join(tid, NULL);
if ( ret != )
{
perror("ptread_join error\n");
return -;
} return ;
}

  不过我仍然感觉有问题,如果A线程执行了多次循环,也就是说条件改变了多次,通知了多次,B线程如果跑的慢只执行了一遍,那么通知是否被丢失了?

  这里采用while( 条件 == FALSE )这种结构是有原因的,pthread_cond_signal man上说的是可以唤醒至少1个等待cond的线程,pthread_cond_broadcast 可以唤醒所有等待cond的线程。假设采用pthread_cond_signal,它唤醒了多个线程,然后有一个线程抢到先执行,wait出来后锁住, 改变条件,解锁,等到另一个被唤醒的线程抢到锁时,发现条件依然为FALSE,它就不会再去执行改变条件的操作了,而是继续等待,这样确保signal唤 醒的线程只会有一个执行改变条件的操作。

linux多线程同步pthread_cond_XXX条件变量的理解的更多相关文章

  1. Linux多线程编程的条件变量

    在stackoverflow上看到一关于多线程条件变量的问题,题主问道:什么时候会用到条件变量,mutex还不够吗?有个叫slowjelj的人做了很好的回答,我再看这个哥们其他话题的一些回答,感觉水平 ...

  2. Linux线程同步:条件变量

    条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用.使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化.一旦其它 ...

  3. linux线程同步(2)-条件变量

    一.概述                                                    上一篇,介绍了互斥量.条件变量与互斥量不同,互斥量是防止多线程同时访问共享的互斥变量来保 ...

  4. Linux 多线程编程—使用条件变量实现循环打印

    编写一个程序,开启3个线程,这3个线程的ID分别为A.B.C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示:如:ABCABC….依次递推. 使用条件变量来实现: #inc ...

  5. Linux多线程同步之相互排斥量和条件变量

    1. 什么是相互排斥量 相互排斥量从本质上说是一把锁,在訪问共享资源前对相互排斥量进行加锁,在訪问完毕后释放相互排斥量上的锁. 对相互排斥量进行加锁以后,不论什么其它试图再次对相互排斥量加锁的线程将会 ...

  6. Linux互斥锁、条件变量和信号量

    Linux互斥锁.条件变量和信号量  来自http://kongweile.iteye.com/blog/1155490 http://www.cnblogs.com/qingxia/archive/ ...

  7. linux 互斥锁和条件变量

    为什么有条件变量? 请参看一个线程等待某种事件发生 注意:本文是linux c版本的条件变量和互斥锁(mutex),不是C++的. mutex : mutual exclusion(相互排斥) 1,互 ...

  8. 练习生产者与消费者-PYTHON多线程中的条件变量同步-Queue

    以前练习过,但好久不用,手生,概念也生了, 重温一下.. URL: http://www.cnblogs.com/holbrook/tag/%E5%A4%9A%E7%BA%BF%E7%A8%8B/ ~ ...

  9. linux C++ 多线程使用pthread_cond 条件变量

    1. 背景 多线程中经常需要使用到锁(pthread_mutex_t)来完成多个线程之间的互斥操作. 但是互斥锁有一个明显到缺点: 只有两种状态,锁定和非锁定. 而条件变量则通过允许线程阻塞并等待另一 ...

随机推荐

  1. iOS7 UI兼容 导航栏按钮边框 UINavigationItem left and right padding

    iOS7之前的UI为: 而在iOS7中,由于设计方面的原因,使得UI变为: 修改的方法重写UINavigationItem的setLeftBarButtonItem和setRightBarButton ...

  2. [转]在SqlServer 中解析JSON数据

      在Sqlserver中可以直接处理Xml格式的数据,但因为项目需要所以要保存JSON格式的数据到Sqlserver中在博客:Consuming JSON Strings in SQL Server ...

  3. BI之SSAS完整实战教程7 -- 设计维度、细化维度中 :浏览维度,细化维度

    上篇文章我们已经将Dim Geography维度设计好. 若要查看维度的成员, AS需要接收该维度的详细信息(包括已创建的特性.成员属性以及多级层次结构), 通过XMLA与AS的实例进行通信. 今天我 ...

  4. 用C#打开文件对话框的方法和简单使用的程序

  5. learning sql (second edition) script

    create database bank; use bank; /* begin table creation */ create table department (dept_id smallint ...

  6. ruby on rails 2.3+的版本不再支持cgi

    ruby on rails 2.3+的版本不再支持cgi了,恶心到了,换其他框架,看了款cramp,完全没资料,完全不让人入门 操蛋的厉害,ruby果然是小众的窝里乐,放弃使用

  7. [js开源组件开发]js手机联动选择地区仿ios 开源git

    js手机联动选择地区 前言:由于网上找到了一个mobiscrool,比较全,但是不开源,只能试用15天,正式版竟然要三千块钱,穷人只能自己动手,写了个只针对弹窗地区选择的. 本站点所有的资源均在git ...

  8. 用js枚举实现简易菜单效果

    用js枚举实现简易菜单效果,左侧显示菜单,右侧显示用户选择的菜单,一图胜千言,还是直接来张效果图吧: 以下是代码: <DOCTYPE html> <html> <head ...

  9. Sharepoint学习笔记—习题系列--70-573习题解析 -(Q104-Q106)

    Question 104You plan to create a workflow that has the following three activities: CreateTask OnTask ...

  10. cocospods的安装与应用

    安装cocospods 一,升级Ruby环境 ~ xxx$ sudo gem update --system   二,安装Cocoapods时需要访问cocoapods.org,该网站可能被墙掉,但是 ...