线程同步之条件变量

原创 2016年08月30日 18:20:34

与互斥锁不同,条件变量是用来等待而不是用来上锁的。条件变量用来自动阻塞一个线程,直到某特殊情况发生为止通常条件变量和互斥锁同时使用。

条件变量使我们可以睡眠等待某种条件出现。条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。

条件的检测是在互斥锁的保护下进行的。如果一个条件为假,一个线程自动阻塞,并释放等待状态改变的互斥锁。如果另一个线程改变了条件,它发信号给关联的条件变量,唤醒一个或多个等待它的线程,重新获得互斥锁,重新评价条件。如果两进程共享可读写的内存,条件变量可以被用来实现这两进程间的线程同步。

使用条件变量之前要先进行初始化。可以在单个语句中生成和初始化一个条件变量如:pthread_cond_t my_condition=PTHREAD_COND_INITIALIZER;(用于进程间线程的通信)。可以利用函数pthread_cond_init动态初始化。

条件变量分为两部分: 条件和变量. 条件本身是由互斥量保护的. 线程在改变条件状态前先要锁住互斥量. 它利用线程间共享的全局变量进行同步的一种机制。

相关的函数如下:

1 int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr);     
2 int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
3 int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);
4 int pthread_cond_destroy(pthread_cond_t *cond);  
5 int pthread_cond_signal(pthread_cond_t *cond);
6 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
 

详细说明

1. 初始化:

    条件变量采用的数据类型是pthread_cond_t, 在使用之前必须要进行初始化, 这包括两种方式:

  • 静态: 可以把常量PTHREAD_COND_INITIALIZER给静态分配的条件变量.
  • 动态: pthread_cond_init函数, 是释放动态条件变量的内存空间之前, 要用pthread_cond_destroy对其进行清理.

#include <pthread.h>

int pthread_cond_init(pthread_cond_t *restrict cond, pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);

成功则返回0, 出错则返回错误编号.

    当pthread_cond_init的attr参数为NULL时, 会创建一个默认属性的条件变量; 非默认情况以后讨论.

2. 等待条件:

#include <pthread.h>

int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restric mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict timeout);

成功则返回0, 出错则返回错误编号.

    这两个函数分别是阻塞等待和超时等待.

    等待条件函数等待条件变为真, 传递给pthread_cond_wait的互斥量对条件进行保护, 调用者把锁住的互斥量传递给函数. 函数把调用线程放到等待条件的线程列表上, 然后对互斥量解锁, 这两个操作是原子的. 这样便关闭了条件检查和线程进入休眠状态等待条件改变这两个操作之间的时间通道, 这样线程就不会错过条件的任何变化.

    当pthread_cond_wait返回时, 互斥量再次被锁住.

3. 通知条件:

#include <pthread.h>

int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);

成功则返回0, 出错则返回错误编号.

    这两个函数用于通知线程条件已经满足. 调用这两个函数, 也称向线程或条件发送信号. 必须注意, 一定要在改变条件状态以后再给线程发送信号.


//用户从终端输入任意字符然后统计个数显示,输入end则结束
//使用多线程实现:主线程获取用户输入并判断是否退出,子线程计数
#include<stdio.h>
#include <pthread.h>
#include<stdlib.h>
#include <string.h>
#include <semaphore.h>



pthread_mutex_t mutex;      
char buf[100]={0}; 
int flag;
pthread_cond_t cond;


// 子线程程序,作用是统计buf中的字符个数并打印
void *func(void*arg)
{
	// 子线程首先应该有个循环
	// 循环中阻塞在等待主线程激活的时候,子线程被激活后就去获取buf中的字符
	// 长度,然后打印;完成后再次被阻塞
    //sleep(1);//防止先运行子线程
	while(flag==0)
	{
		pthread_mutex_lock(&mutex);
		pthread_cond_wait(&cond, &mutex);
		printf("长度为:%d.\n",strlen(buf));
		memset(buf, 0, sizeof(buf));
	    pthread_mutex_unlock(&mutex);
		//sleep(1);          //防止不断在子线程中打印
	}
	
    pthread_exit(NULL);
	
}

int main(void)
{
	int ret=-1;
	pthread_t th;
	
	pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);         
	
	ret=pthread_create(&th,NULL,func,NULL);
    if (ret != 0)
	{
		printf("pthread_create error.\n");
		return -1;
	}                    
	
	printf("输入一个字符串,以回车结束.\n");
	
	while(1)
	{
		
		
		scanf("%s",buf);
		pthread_cond_signal(&cond);
		// 去比较用户输入的是不是end,如果是则退出,如果不是则继续	
		if(!strncmp(buf,"end",3))
		{
			printf("输入的字符串为:%s",buf);
			flag==1;
			
			break;
		}
		// 主线程在收到用户收入的字符串,并且确认不是end后
		// 就去发信号激活子线程来计数。
		// 子线程被阻塞,主线程可以激活,这就是线程的同步问题。
		// 信号量就可以用来实现这个线程同步	
	    //sleep(1);//防止不断在主线程中不断打印
    }
	
	/*
	// 回收子线程
	printf("等待回收子线程\n");
	ret = pthread_join(th, NULL);
	if (ret != 0)
	{
		printf("pthread_join error.\n");
		exit(-1);
	}
	printf("子线程回收成功\n");
	pthread_cond_destroy(&cond);
	pthread_mutex_destroy(&mutex);
	*/
	return 0;
	
}
结果:
输入一个字符串,以回车结束.
asdfsd
长度为:6.
asdsa
长度为:5.
end
输入的字符串为:end























版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

线程同步 条件变量

  • 2016年06月02日 19:39
  • 2KB
  • 下载

boost线程同步(2)——条件变量(POSIX)

boost是一个优秀的跨平台c++库,既然是跨平台那么它肯定封装了许多与具体的操作系统相关的内容。比如,windows和linux在文件系统、线程操作等等上有许多的不同之处,而boost封装了其中的差...
  • mawood
  • mawood
  • 2016年06月02日 23:30
  • 209

线程同步之mutex和条件变量

并发编程有两种基本模型,一种是消息传递,另一种是共享内存。在分布式系统中,运行在多台机器上的多个进程的并行编程只有消息传递。在多线程编程中,消息传递更容易保证程序的正确性。在用C/C++编写多线程程序...

UNIX环境高级编程——线程同步之条件变量以及属性

条件变量变量也是出自POSIX线程标准,另一种线程同步机制。 主要用来等待某个条件的发生。可以用来同步同一进程中的各个线程。当然如果一个条件变量存放在多个进程共享的某个内存区中,那么还可以通过条件变...

线程同步:何时互斥锁不够,还需要条件变量?

很显然,pthread中的条件变量与Java中的wait,notify类似假设有共享的资源sum,与之相关联的mutex 是lock_s.假设每个线程对sum的操作很简单的,与sum的状态无关,比如只...

谈谈对unix线程同步方法(条件变量)的理解

条件变量是一种机制,它允许线程等待某些事件的发生。几个线程可以等待同一个条件变量直到其他线程激活该条件变量为止,这类似于发送一个通知。 条件变量需要由互斥量来保护,线程在改变条件状态前必须先锁住互斥...
  • rbf926
  • rbf926
  • 2012年08月26日 13:53
  • 257

线程同步-条件变量-unix网络编程

1.条件变量的概念          条件变量是一种机制,它允许线程等待某些事件的发生。几个线程可以等待同一个条件变量直到其他线程激活该条件变量为止,这类似于发送一个通知。这时,可以是一个线程被唤醒...

线程同步:何时互斥锁不够,还需要条件变量?

线程同步:何时互斥锁不够,还需要条件变量? 很显然,pthread中的条件变量与Java中的wait,notify类似 假设有共享的资源sum,与之相关联的mutex 是lock_s.假设...
  • qbw2010
  • qbw2010
  • 2015年12月15日 17:13
  • 200

线程同步:条件变量实现生产者消费者模型

概念:   假设实现一个生产者消费者模型,仓库只能装100万件item,生产者每次生产1件,消费者每次消费1件,为了保持数据的同步,那么生产者每次都需要检查仓库是否满了,消费者每次都需要检查仓库是否空...

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

linux线程同步(2)-条件变量 一.概述                                                    上一篇,介绍了互斥量。条件变量与互斥量不同,...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:线程同步之条件变量
举报原因:
原因补充:

(最多只允许输入30个字)