千家信息网

Linux如何实现条件变量

发表于:2024-11-22 作者:千家信息网编辑
千家信息网最后更新 2024年11月22日,这篇文章给大家分享的是有关Linux如何实现条件变量的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。条件变量是用来等待线程而不是上锁的,条件变量通常和互斥锁一起使用。条件变量
千家信息网最后更新 2024年11月22日Linux如何实现条件变量

这篇文章给大家分享的是有关Linux如何实现条件变量的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

条件变量是用来等待线程而不是上锁的,条件变量通常和互斥锁一起使用。条件变量之所以要和互斥锁一起使用,主要是因为互斥锁的一个明显的特点就是它只有两种状态:锁定和非锁定,而条件变量可以通过允许线程阻塞和等待另一个线程发送信号来弥补互斥锁的不足,所以互斥锁和条件变量通常一起使用。

当条件满足的时候,线程通常解锁并等待该条件发生变化,一旦另一个线程修改了环境变量,就会通知相应的环境变量唤醒一个或者多个被这个条件变量阻塞的线程。这些被唤醒的线程将重新上锁,并测试条件是否满足。一般来说条件变量被用于线程间的同步;当条件不满足的时候,允许其中的一个执行流挂起和等待。

简而言之,条件变量本身不是锁,但它也可以造成线程阻塞,通常与互斥锁配合使用,给多线程提供一个会合的场所。

条件变量的优点:

  • 相较于mutex而言,条件变量可以减少竞争。如果仅仅是mutex,那么,不管共享资源里有没数据,生产者及所有消费都全一窝蜂的去抢锁,会造成资源的浪费。

  • 如直接使用mutex,除了生产者、消费者之间要竞争互斥量以外,消费者之间也需要竞争互斥量,但如果汇聚(链表)中没有数据,消费者之间竞争互斥锁是无意义的。有了条件变量机制以后,只有生产者完成生产,才会引起消费者之间的竞争。提高了程序效率。

主要应用函数:

  • pthread_cond_init函数

  • pthread_cond_destroy函数

  • pthread_cond_wait函数

  • pthread_cond_timedwait函数

  • pthread_cond_signal函数

  • pthread_cond_broadcast函数

以上6 个函数的返回值都是:成功返回0, 失败直接返回错误号。

pthread_cond_t类型:用于定义条件变量,比如:pthread_cond_t cond;

##pthread_cond_init函数

函数原型:

int pthread_cond_init(pthread_cond_t restrict cond, const pthread_condattr_t restrict attr);

函数作用:初始化一个条件变量

参数说明:

  • cond:条件变量,调用时应传&cond给该函数

  • attr:条件变量属性,通常传NULL,表示使用默认属性

也可以使用静态初始化的方法,初始化条件变量:

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

##pthread_cond_destroy函数

函数原型:

int pthread_cond_destroy(pthread_cond_t *cond);

函数作用:销毁一个条件变量

##pthread_cond_wait函数

函数原型:

int pthread_cond_wait(pthread_cond_t restrict cond, pthread_mutex_t restrict mutex);

函数作用:

阻塞等待一个条件变量。具体而言有以下三个作用:

  • 阻塞等待条件变量cond(参1)满足;

  • 释放已掌握的互斥锁mutex(解锁互斥量)相当于pthread_mutex_unlock(&mutex);

  • 当被唤醒,pthread_cond_wait函数返回时,解除阻塞并重新申请获取互斥锁

其中1、2.两步为一个原子操作。

##pthread_cond_timedwait函数

函数原型:

int pthread_cond_timedwait(pthread_cond_t restrict cond, pthread_mutex_t restrict mutex, const struct timespec *restrict abstime);

函数作用:限时等待一个条件变量

参数说明:

前两个比较好理解,重点说明第三个参数。

这里有个struct timespec结构体,可以在man sem_timedwait中查看。结构体原型如下:

struct timespec {  time_t tv_sec; / seconds / 秒   long tv_nsec; / nanosecondes/ 纳秒  }

struct timespec定义的形参abstime是个绝对时间。注意,是绝对时间,不是相对时间。什么是绝对时间?2018年10月1日10:10:00,这就是一个绝对时间。什么是相对时间?给洗衣机定时30分钟洗衣服,就是一个相对时间,也就是说从当时时间开始计算30分钟,诸如此类。

如:time(NULL)返回的就是绝对时间。而alarm(1)是相对时间,相对当前时间定时1秒钟。

adstime所相对的时间是相对于1970年1月1日00:00:00,也就是UNIX计时元年。

下面给出一个错误用法: struct timespec t = {1, 0}; pthread_cond_timedwait (&cond, &mutex, &t); 这种用法只能定时到 1970年1月1日 00:00:01秒,想必这个时间大家都还没出生。

正确用法: time_t cur = time(NULL); 获取当前时间。 struct timespec t; 定义timespec 结构体变量t t.tv_sec = cur+1; 定时1秒 pthread_cond_timedwait (&cond, &mutex, &t); 传参

##pthread_cond_signal函数

函数原型:

int pthread_cond_signal(pthread_cond_t *cond);

函数作用: 唤醒至少一个阻塞在条件变量上的线程

##pthread_cond_broadcast函数

函数原型:

int pthread_cond_broadcast(pthread_cond_t *cond);

函数作用: 唤醒全部阻塞在条件变量上的线程

##生产者消费者条件变量模型

不管是什么语言,只要提到线程同步,一个典型的案例就是生产者消费者模型。在Linux环境下,借助条件变量来实现这一模型,是比较常见的一种方法。

假定有两个线程,一个模拟生产者行为,一个模拟消费者行为。两个线程同时操作一个共享资源(一般称之为汇聚),生产向其中添加产品,消费者从中消费掉产品。

看如下示例,使用条件变量模拟生产者、消费者问题:

#include  #include #include #include typedef struct msg {    struct msg *next;     int num;}msg_t;msg_t *head = NULL;msg_t *mp = NULL;/* 静态初始化 一个条件变量 和 一个互斥量*/pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;pthread_mutex_t mutex =PTHREAD_MUTEX_INITIALIZER;void *th_producer(void *arg) {    while (1) {         mp = malloc(sizeof(msg_t));        mp->num = rand() % 1000;        //模拟生产一个产品         printf("--- produce: %d --------\n", mp->num);         pthread_mutex_lock(&mutex);        mp->next = head;         head = mp;        pthread_mutex_unlock(&mutex);        pthread_cond_signal(&has_product);      //唤醒线程去消费产品        sleep(rand() % 5);     }    return NULL; }void *th_consumer(void *arg) {    while (1) {         pthread_mutex_lock(&mutex);        while (head == NULL) {      //如果链表里没有产品,就没有抢锁的必要,一直阻塞等待             pthread_cond_wait(&has_product, &mutex);        }        mp = head;        head = mp->next;        //模拟消费掉一个产品         pthread_mutex_unlock(&mutex);        printf("========= consume: %d ======\n", mp->num);         free(mp);        mp = NULL;        sleep(rand() % 5);     }    return NULL; }int main(){    pthread_t pid, cid;    srand(time(NULL));     pthread_create(&pid, NULL, th_producer, NULL);    pthread_create(&cid, NULL, th_consumer, NULL);    pthread_join(pid, NULL);    pthread_join(cid, NULL);    return 0; }

运行结果:


感谢各位的阅读!关于"Linux如何实现条件变量"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

条件 变量 函数 线程 时间 消费 生产 消费者 阻塞 作用 原型 生产者 产品 就是 竞争 之间 两个 参数 模型 环境 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 公司打不开服务器 蓬莱微信公众号软件开发哪家好 网络安全电竞游戏 通保二级通信网络安全防护培训 腾讯数据库会保存多久的记录 流放之路破空斩数据库 软件开发高级工程师述职演讲稿 网络技术创新平台 保护儿童网络安全 手机登录不了连接服务器失败 如何导入另一个ssx数据库 怎么绕过安全狗下载数据库 舟山数据库审计系统功能 磐石桌面系统服务器地址填什么 w10连不上微软服务器 数据库ssf33加密方法 哪家公司服务器便宜 cs hns服务器 已经写入数据库的数据会丢失吗 怎么查看APP所连接的服务器 聚合服务器部署 服务器负载均衡测试方案 虚拟机中查看当前服务器的主机名 vb EXE打开数据库报错 软件开发软件服务合同模板 计算机网络技术三级考试问题 智能汽车软件开发培训 最常用的数据库是什么意思 初中生能学计算机网络技术吗 java应用程序的数据库
0