当前位置: 首页 > news >正文

嵌入式Linux:线程同步(条件变量)

目录

1、条件变量的初始化和销毁

2、发送信号和等待条件变量

3、条件变量中的判断条件


在Linux环境下,条件变量(Condition Variables)是一种线程同步机制,允许线程在某个条件未满足时进入等待状态,并在其他线程修改共享资源或条件后通知它们。条件变量和互斥锁通常一起使用,以保证对共享资源的安全访问。通过条件变量,线程可以避免忙等待(busy-waiting),从而提高效率。

条件变量使得线程可以通过以下方式同步:

  • 等待某个条件满足:当某个线程在等待某个条件时,它可以进入阻塞状态,并释放持有的互斥锁,以允许其他线程操作共享资源。
  • 通知条件满足:当其他线程改变了共享资源的状态,且满足了等待线程的条件,它可以通过发送信号(signal)来通知那些正在等待的线程,使它们被唤醒并继续执行。

条件变量通常与互斥锁结合使用,因为在检查或修改某些共享资源时,需要保护这些资源的并发访问,防止竞争条件。

互斥锁负责保护共享资源,条件变量负责在线程间传递状态信息。具体步骤如下:

  • 线程通过互斥锁访问共享资源。
  • 当条件未满足时,线程通过条件变量进入等待,并释放互斥锁,允许其他线程继续操作资源。
  • 其他线程修改共享资源并发出条件满足的信号,通知条件变量唤醒等待线程。
  • 被唤醒的线程重新获得互斥锁并检查条件是否满足,如果满足则继续执行,否则继续等待。

条件变量的使用步骤:

  • 初始化条件变量和互斥锁。
  • 在线程中使用互斥锁对共享资源进行保护。
  • 如果条件未满足,调用pthread_cond_wait()使线程进入阻塞状态,同时释放互斥锁,等待其他线程通知条件满足。
  • 其他线程修改共享资源后,调用pthread_cond_signal()pthread_cond_broadcast()通知等待线程。
  • 被唤醒的线程重新获得互斥锁并继续检查条件。

1、条件变量的初始化和销毁

条件变量使用pthread_cond_t数据类型来表示,和互斥锁类似,条件变量在使用前必须初始化。可以通过两种方式进行初始化:

使用宏PTHREAD_COND_INITIALIZER,类似于互斥锁的静态初始化方式:

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

使用pthread_cond_init()函数动态初始化条件变量:

pthread_cond_init(&cond, NULL); // attr 为 NULL 时使用默认属性

参数

  • cond: 指向待初始化的条件变量对象,类型为 pthread_cond_t*
  • attr: 条件变量的属性,可以为 NULL 表示使用默认属性。

返回值

  • 成功返回 0
  • 失败返回非零错误码,如 EINVAL(无效属性)。

当不再使用条件变量时,应使用pthread_cond_destroy()进行销毁,以释放系统资源,销毁前需要确保没有线程在等待该条件变量。

pthread_cond_destroy(&cond);

参数

  • cond: 指向待销毁的条件变量对象。

返回值

  • 成功返回 0
  • 失败返回非零错误码,如 EBUSY(有线程在等待该条件变量)。

注意事项

  • 只能销毁已经初始化的条件变量。
  • 条件变量销毁时,不能有线程在等待它,否则将导致未定义行为。

2、发送信号和等待条件变量

条件变量的核心功能就是发送信号和等待条件。在多线程程序中,线程通过pthread_cond_wait()等待条件,而其他线程通过pthread_cond_signal()pthread_cond_broadcast()发出信号。

pthread_cond_wait():使线程等待条件满足,并在等待期间释放互斥锁。该函数会阻塞调用线程,直到另一个线程调用 pthread_cond_signal()pthread_cond_broadcast() 通知该条件变量。

#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);

参数

  • cond: 条件变量指针,指向 pthread_cond_t 类型的条件变量。
  • mutex: 互斥锁指针,指向 pthread_mutex_t 类型的互斥锁。在线程进入等待状态时,pthread_cond_wait 会自动释放该互斥锁,并在线程被唤醒时重新加锁。

返回值

  • 成功返回 0
  • 失败返回非零错误码。

注意事项

  • 在调用 pthread_cond_wait() 之前,必须先锁住互斥锁,以避免条件检查和等待之间的竞争。
  • 线程被唤醒时,会重新锁住传入的互斥锁。

pthread_cond_signal():用于通知至少一个等待该条件变量的线程,使其从 pthread_cond_wait() 的阻塞状态中唤醒。如果没有线程在等待条件变量,该信号会被丢弃。

#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);

参数

  • cond: 条件变量指针,指向 pthread_cond_t 类型的条件变量。

返回值

  • 成功返回 0
  • 失败返回非零错误码。

注意事项

  • 该函数只能唤醒一个等待的线程。
  • 如果没有线程等待,信号不会累积,因此没有线程在等待时,调用该函数不会有任何效果。

pthread_cond_broadcast():用于唤醒所有等待该条件变量的线程。适用于需要唤醒多个线程的场景。

#include <pthread.h>
int pthread_cond_broadcast(pthread_cond_t *cond);

参数

  • cond: 条件变量指针,指向 pthread_cond_t 类型的条件变量。

返回值

  • 成功返回 0
  • 失败返回非零错误码。

假设有多个消费者线程在等待产品,如果使用pthread_cond_signal(),只有一个线程会被唤醒。如果我们希望所有消费者都被唤醒,则使用pthread_cond_broadcast()。但一般来说,pthread_cond_signal()更高效,除非确实需要所有线程都被唤醒。

pthread_cond_signal(&cond);   // 唤醒一个线程
pthread_cond_broadcast(&cond); // 唤醒所有等待的线程

3、条件变量中的判断条件

在使用条件变量时,通常涉及某个共享变量(如上例中的buffer)。在检测条件时,必须使用while循环而非if语句。这是因为:

  • 虚假唤醒:线程可能被意外唤醒,但条件仍不满足。用while循环可以确保条件再次检查,而不是立即继续执行。
  • 竞争条件:多个线程可能同时被唤醒,但只有一个线程会成功获取锁并修改条件状态。其他线程必须再次等待。

这样设计能确保线程在条件不满足时不会继续执行,从而避免竞争条件带来的问题。

pthread_mutex_lock(&mutex);
while (buffer == 0) {pthread_cond_wait(&cond, &mutex);
}

以下示例展示了生产者-消费者模型,其中生产者线程和消费者线程通过条件变量进行同步:

#include <pthread.h>
#include <stdio.h>pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int buffer = 0;  // 缓冲区,0表示空,1表示有产品void *producer(void *arg) {pthread_mutex_lock(&mutex);  // 加锁while (buffer == 1) {pthread_cond_wait(&cond, &mutex);  // 缓冲区满,等待}buffer = 1;  // 生产产品printf("Produced an item\n");pthread_cond_signal(&cond);  // 通知消费者pthread_mutex_unlock(&mutex);  // 解锁return NULL;
}void *consumer(void *arg) {pthread_mutex_lock(&mutex);  // 加锁while (buffer == 0) {pthread_cond_wait(&cond, &mutex);  // 缓冲区空,等待}buffer = 0;  // 消费产品printf("Consumed an item\n");pthread_cond_signal(&cond);  // 通知生产者pthread_mutex_unlock(&mutex);  // 解锁return NULL;
}int main() {pthread_t prod, cons;// 创建生产者和消费者线程pthread_create(&prod, NULL, producer, NULL);pthread_create(&cons, NULL, consumer, NULL);// 等待线程执行完毕pthread_join(prod, NULL);pthread_join(cons, NULL);// 销毁互斥锁和条件变量pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);return 0;
}

Linux中的条件变量是线程同步的强大工具,允许线程等待特定条件满足后再执行操作,避免了无效的忙等待。通过与互斥锁协作,条件变量可以有效地协调线程之间对共享资源的访问,保证并发环境下的安全性和效率。

  • 条件变量与互斥锁结合使用:条件变量用于等待和通知条件变化,互斥锁则用于保护共享资源的访问。
  • 条件变量不保存状态:如果没有线程在等待条件变量,信号会丢失。
  • pthread_cond_wait()应放在循环中:因为多个线程可能竞争资源,因此从 pthread_cond_wait() 返回后应重新检查条件。
  • 选择合适的通知方式pthread_cond_signal() 唤醒一个等待线程,pthread_cond_broadcast() 唤醒所有等待线程。
http://www.dtcms.com/a/499231.html

相关文章:

  • 从“小而美”到“大而强”:音视频直播SDK的技术进化逻辑
  • 2五、buildroot支持Qt5
  • 我做的网站怎么打开很慢电信网络运营商
  • 敦化网站开发淘宝网网页版登录平台
  • Umi-OCR制作双层PDF
  • TD 通达OAOAV12.9版本的密码重置
  • 【办公类-115-02】20251018信息员每周通讯上传之文字稿整理(PDF转docx没有成功)
  • MySQL表设计详解
  • AI 编程 Trae ,有重大更新!用 Trae 做了个图书借阅网站!
  • 手机可以搭建网站么深圳软件开发工作室
  • 网站模板建设教程都江堰网站建设
  • 字符串相关OJ题解析(图文并茂+过程演示)
  • 分治算法-归并排序专题:从性能优化到索引数组的突破
  • iis怎么做IP网站有没有专门做数据分析的网站
  • 如何用 Docker Compose 管理多个容器
  • 《C++ STL 基础入门》教案
  • 基于对数灰关联度的IOWGA算子最优组合预测模型
  • VGW 技术解析:构建 Windows 平台的虚拟路由网关中枢
  • 内容安全优化:基于Redis实现分级反爬虫策略
  • 生成式设计案例:MG AEC利用Autodesk AEC Collection推进可持续建筑设计
  • 物流网站源代码修改wordpress后台文字
  • 【HTML】网络数据是如何渲染成HTML网页页面显示的
  • 做门图网站产品品牌推广公司
  • linux学习笔记(38)mysql索引详解
  • M1安装RocketMQ消息队列
  • 广西壮族自治区住房和城乡建设厅网站网站内页制作
  • PDFium导出pdf 图像
  • C++11标准 上 (万字解析)
  • Java基础语法—字面量、变量详解、存储数据原理
  • 手工视频制作网站移动网站建设初学视频教程