深入理解Linux 条件变量1:使用场景、接口说明

本文探讨了多线程编程中的线程同步与等待问题,介绍了条件变量的概念及其在生产者/消费者模式中的应用,对比了轮询与条件变量两种等待机制的优劣。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

在多线程编程中,涉及到线程并发,我们一般会有2种需求,一种是线程同步,一种是线程等待
线程同步一般指两个或多个线程同时访问同一个资源,这里的并不是同时,而是协同的含义,比如两个线程同时操作某个串口,某个fd等等,这个时候就需要同步,我们一般会使用互斥锁来实现,互斥锁又叫互斥量。
线程等待的典型场景就是【生产/消费】模式,一个或多个线程负责生产数据,而另外的消费线程负责消费数据。我们以自定义消息队列举例,生产线程负责往消息队列里写数据,而消费线程负责从消息队列里读数据,我们一般都希望消费能够及时,针对这种情况,我们很容易想到在消费线程里进行轮训,伪代码如下:

void *thread_producer(void *arg)
{	
	inser_msg_to_queue(msg_queue, data);
}

void *thread_consumer(void *arg)
{
	while(1){
		if(!msg_queue_is_empty(msg_queue)){
			data = get_msg_from_queue(msg_queue);
		}
	}
}

上面的代码就是典型的使用轮询的方式去查询消息队列是否有数据,这种方式实现起来比较简单,实时性也能保证,但是有个明显的缺点,就是CPU利用率低,因为生产线程的生产数据频率是随时的,而消费线程确在不停的轮询,会导致CPU占用率高。针对该原因,我们一般会增加个延时进行轮询,修改方案如下:

void *thread_producer(void *arg)
{	
	inser_msg_to_queue(msg_queue, data);
}

void *thread_consumer(void *arg)
{
	while(1){
		if(!msg_queue_is_empty(msg_queue)){
			data = get_msg_from_queue(msg_queue);
		}
		usleep(100000);			// 100ms
	}
}

这种优化方案能够有效的帮助上面说的缺点,如果对于实时性要求不那么高,这种方式也是可取的,因为这种方式有一个最大的优点,就是容易实现,并且可移植性高,能够很方便的跨平台。不过凡事都不是绝对的,我们有没有更好的办法呢?既能够保消费实时性,又能够最大限度的利用CPU,答案是:在linux平台下,条件变量可以满足我们的需求。

条件变量说明

在Unix环境高级编程中,对条件变量的定义是:

条件变量是线程可用的一种同步机制,条件变量给多个线程提供了一个会合的场所,条件变量与互斥量一起使用时,允许线程以无竞争的方式等待特定的条件发生。

从上面的解释可以发现,条件变量的功能就在于条件二字,可以结合上面的生产/消费模式,在消费线程中等待条件符合,然后进行消费,而在生产线程中,则需要创造并发送条件给消费线程。而条件本身也是一种【资源】,所以条件变量也需要由互斥锁进行保护,所以条件变量的使用一般会伴随着互斥锁,后面我们会专题讲述条件变量为什么需要配合着互斥锁来使用。

条件变量相关API

#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_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);

// 带有超时功能的 等待条件变量
int pthread_cond_timedwait(pthread_cond_t *restrict cond, 
						pthread_mutex_t *restrict mutex,
						const struct timespec *restrict tsptr);

// 通知条件变量,唤醒至少1个等待该条件的线程
int pthread_cond_signal(pthread_cond_t *cond);

// 通知条件变量,广播唤醒等待该条件的所有线程
int pthread_cond_broadcast(pthread_cond_t *cond);

小结

  1. 条件变量是 实现线程 等待的一种便利方式。
  2. 条件变量本身并不会关联业务,需要开发者在自己的生产、消费线程中使用条件变量,具体表现为,在生产线程中调用pthread_cond_signal, 在消费线程中调用pthread_cond_wait。
  3. 条件变量的使用,特别像linux链表的实现方式,在list.h中,定义了 struct slist_s 结构体,这个结构体中只有 next 指针,并没有包括开发者自己的 消息内容,我们在使用的时候,只需要在自己的消息数据结构里包含一个 struct slist_s list 即可实现链表的管理。条件变量也是一样的,条件变量就是独立的,也可以简单的理解为一个带有信号功能的计数器,pthread_cond_sign往计数器里递增数据,并且发送信号,告诉调用pthread_cond_wait的线程,条件变量状态变了,不用再等待了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值