并发编程之条件变量

本文介绍了线程中的条件变量,一种用于线程间同步的机制,通过等待和信号操作实现线程间的协作。条件变量通常与互斥锁结合使用,避免竞争条件。在生产者消费者模型中,条件变量能减少不必要的锁竞争,提高程序效率。文中还给出了使用pthread库实现的条件变量示例代码,展示了如何在多线程环境中解决生产者消费者问题。

1.概念

线程中的一个概念,和进程中的信号的概念很像,等待某一个条件的发生。条件变量可以使得线程睡眠以等待某种条件的发生。它是利用线程间共享的全局变量进行线程间同步的一种机制,主要包含两个动作:线程为等待其他线程的某个条件成立而挂起,线程满足了某个条件而向其他线程发出信号。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。条件变量会造成线程阻塞,它作为一个线程之间通信的方式,给多线程提供了一个会合的场所。

2.相关主要函数及变量类型

 头文件:
 #include <pthread.h>
 函数定义:
 int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict  attr);// 初始化一个条件变量
 int pthread_cond_destroy(pthread_cond_t *cond);//销毁一个条件变量
 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);//阻塞等待一个条件变量
 int pthread_cond_broadcast(pthread_cond_t *cond);//当条件变量满足时,该函数可唤醒阻塞在条件上的所有线程
 int pthread_cond_signal(pthread_cond_t *cond);//当条件变量满足时,该函数可唤醒阻塞在条件上的至少一个线程
 返回值:
 上面6个函数的返回值都是成功返回0,失败直接返回错误号。
  
 pthread_cond_t类型,用于定义条件变量. 

pthread_cond_wait函数说明(阻塞等待一个条件变量,永久阻塞,可比照sigsuspend函数进行学习):
函数的作用:
1.阻塞等待条件变量cond满足;
2.释放已掌握的互斥锁(解锁互斥量),相当于pthread_mutex_unlock(&mutex);(1,2两步是个原子操作)
3.当被唤醒时,pthread_cond_wait函数返回时,解除阻塞并且重新申请获取互斥锁pthread_mutex_lock(&mutex)
在调用pthread_cond_wait之前要有:
(1)定义互斥量和条件变量;
(2)初始化互斥量和条件变量,对互斥量加锁;


pthread_cond_timedwait-限时等待一个条件变量(在一定的时间内是阻塞的)

3.线程同步的经典模型

生产者消费者模型

4.编码演示

/*
作者:Muten
编码时间:20201016
编码目的:演示借助线程中利用条件变量模拟【生产者消费者】问题
代码功能:借助条件变量模拟【生产者消费者】问题

*/
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>

struct msg
{
	struct msg *next;
	int num;
};

struct msg *head;
struct msg *mp;

/*静态方式初始化一个条件变量和一个互斥量*/
pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

void *consumer(void* p)
{
	for(;;)
	{
		pthread_mutex_lock(&lock);
		while(head == NULL)// 头结点为空说明没有节点
		{ 
			pthread_cond_wait(&has_product,&lock);//一旦调用pthread_cond_wait会放弃lock这个互斥量
		}
		mp = head;
		head = mp->next;
		pthread_mutex_unlock(&lock);
		printf("--Consumer----%d.\n",mp->num);
		free(p);
		p = NULL;
		sleep(rand()%5);  
	}
}

//生产者县线程调用的函数
void *producer(void* p)
{
	for(;;)
	{
		mp = malloc(sizeof(struct msg));
		mp->num = rand()%1000 +1;
		printf("--Producer----%d.\n",mp->num);
		pthread_mutex_lock(&lock);//这里可以执行成功,消费者一旦调用pthread_cond_wait就把这个互斥量解锁了,所以这里可以可以正常获取互斥锁
		mp->next = head;
		head = mp;//头插法
		pthread_mutex_unlock(&lock);
		pthread_cond_signal(&has_product);
		sleep(rand()%5);  
	}
}

int main()
{
	pthread_t pid ,cid;
	srand(time(NULL));
	pthread_create(&pid,NULL,producer,NULL);
	pthread_create(&pid,NULL,consumer,NULL);
	pthread_join(pid,NULL);
	pthread_join(pid,NULL);
	return 0;
}

5.条件变量的优点

       其实只有mutex已经能够完成我们对共享资源的保护,但为什么又衍生出条件变量和读写锁这些机制呢?这是为了在合适的场景下进一步优化我们的处理流程,使得程序更高效。

   

相较于mutex而言,条件变量可以减少竞争。我们针对上面的生产者消费者模型来分析,如果直接使用mutex,除了生产者消费者之间需要竞争
互斥量以外,消费者之间也需要竞争互斥量,但如果共享资源中不存在数据,消费者之间竞争互斥锁是没有意义的。有了条件变量机制以后,
只有生产者完成生产,才会引起消费者之间的竞争,提高了程序效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值