Linux-----线程同步(条件变量)

news2025/1/19 13:49:10

 目录

相关API

restrict关键字

线程间条件切换函数

条件变量pthread_cond_t

案例


在前面的锁的基础上进一步提高线程同步效率,也就是两个线程只用锁去执行的话依然会存在资源竞争的情况,也就是抢锁,这里就需要在锁的这边加上限制,也就是条件变量,有了条件变量的加持,就可以很好的控制线程与线程之间的协同。 

相关API

restrict关键字

restrict是一个C99标准引入的关键字,用于修饰指针,它的作用是告诉编译器,被修饰的指针是编译器所知的唯一一个可以在其作用域内用来访问指针所指向的对象的方法。这样一来,编译器可以放心地执行代码优化,因为不存在其他的别名(即其他指向同一内存区域的指针)会影响到这块内存的状态。

restrict声明了一种约定,主要目的是允许编译器在生成代码时做出优化假设,而不是在程序的不同部分间强制执行内存访问的规则。程序员需要确保遵守restrict的约定,编译器则依赖这个约定来进行优化。如果restrict约定被违反,可能导致未定义行为。

函数参数使用restrict修饰,相当于约定:函数执行期间,该参数指向的内存区域不会被其它指针修改。

线程间条件切换函数

如果需要两个线程协同工作,可以使用条件变量完成线程切换。查看文档可得:

#include <pthread.h>

/**
 * @brief 调用该方法的线程必须持有mutex锁。调用该方法的线程会阻塞并临时释放mutex锁,并等待其他线程调用pthread_cond_signal或pthread_cond_broadcast唤醒。被唤醒后该线程会尝试重新获取mutex锁。
 * 
 * @param cond 指向条件变量的指针。条件变量用于等待某个条件的发生。通过某一cond等待的线程需要通过同一cond的signal唤醒
 * @param mutex 与条件变量配合使用的互斥锁的指针。在调用pthread_cond_wait之前,线程必须已经获得了这个互斥锁。
 * @return int 成功时返回0;失败时返回错误码,而非-1。错误码可能包括EINVAL、EPERM等,具体取决于错误的性质。
 */
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);

/**
 * @brief 同pthread_cond_wait相似,但是它添加了超时机制。如果在指定的abstime时间内条件变量没有被触发,函数将返回一个超时错误(ETIMEDOUT)。
 * 
 * @param cond 指向条件变量的指针
 * @param mutex 与条件变量配合使用的互斥锁的指针
 * @param abstime 指向timespec结构的指针,表示等待条件变量的绝对超时时间。timespec结构包含秒和纳秒两部分,指定了从某一固定点(如UNIX纪元,1970年1月1日)开始的时间。
 * @return int 成功时返回0;如果超时则返回ETIMEDOUT;其他错误情况返回相应的错误码。
 */

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

/**
 * @brief 唤醒因cond而阻塞的线程,如果有多个线程因为cond阻塞,那么随机唤醒一个。如果没有线程在等待,这个函数什么也不做。
 * 
 * @param cond 指向条件变量的指针
 * @return int 成功时返回0;失败时返回错误码
 */
int pthread_cond_signal(pthread_cond_t *cond);

/**
 * @brief 唤醒所有正在等待条件变量cond的线程。如果没有线程在等待,这个函数什么也不做。
 * 
 * @param cond 指向条件变量的指针。
 * @return int 成功时返回0;失败时返回错误码。
 */
int pthread_cond_broadcast(pthread_cond_t *cond);

  1. 使用条件变量时,通常涉及到一个或多个线程等待“条件变量”代表的条件成立,而另外一些线程在条件成立时触发条件变量。
  2. 条件变量的使用必须与互斥锁配合,以保证对共享资源的访问是互斥的。
  3. 条件变量提供了一种线程间的通信机制,允许线程以无竞争的方式等待特定条件的发生。

条件变量pthread_cond_t

 pthread_cond_t是一个条件变量,它是线程间同步的另一种机制。与pthread_mutex_t相同,它也定义在头文件<pthreadtypes.h>中,其声明如下。

typedef union
{
  struct __pthread_cond_s __data;
  char __size[__SIZEOF_PTHREAD_COND_T];
  __extension__ long long int __align;
} pthread_cond_t;

案例

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
// 同步队列?
#define BUFFER_SIZE 10
int buffer[BUFFER_SIZE];

int count = 0;
// 互斥锁
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

// 初始化调解笔录
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

// 生产者线程函数
void* producer_fun(void* args) {
    int i = 1;
    while (1)
    {
        // 使用共同变量,使用互斥锁
        pthread_mutex_lock(&mutex);

        // 如果缓冲区慢了就要暂停放入
        if (count == BUFFER_SIZE) {
            pthread_cond_wait(&cond, &mutex);
        }
        printf("生产者写入%d\n", i);
        buffer[count++] = i++;
        // 唤醒消费者
        pthread_cond_signal(&cond);
        // 最后释放锁
        pthread_mutex_unlock (&mutex);
    }
    
}
void* consumer_fun(void* args) {
    while (1)
    {
        pthread_mutex_lock(&mutex);
        // 数据读完了
        if (count == 0) {
            pthread_cond_wait(&cond, &mutex);
        }
        printf("消费者收到数据%d\n", buffer[--count]);
        // 唤醒生产者
        pthread_cond_signal(&cond);
        
        pthread_mutex_unlock(&mutex);
    }
    
}

int main(int argc, char const *argv[])
{
    pthread_t producer, consumer;
    // 创建线程
    pthread_create(&producer, NULL, producer_fun, NULL);
    pthread_create(&consumer, NULL, consumer_fun, NULL);

    // 主线程要挂起等待子线程
    pthread_join(producer, NULL);
    pthread_join(consumer, NULL);

    return 0;
}

 上面这个写法还是会存在资源竞争的情况,也就是抢锁,实际上并不是生产者生产后消费者马上执行,而是互相竞争的。下面是修改后:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
// 同步队列?
#define BUFFER_SIZE 10
int buffer[BUFFER_SIZE];

int count = 0;
// 互斥锁
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

// 初始化调解笔录
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

// 生产者线程函数
void* producer_fun(void* args) {
    int i = 1;
    // 使用共同变量,使用互斥锁
    pthread_mutex_lock(&mutex);
    while (1)
    {
        // 如果缓冲区慢了就要暂停放入
        if (count == BUFFER_SIZE) {
            pthread_cond_wait(&cond, &mutex);
            
        }
        printf("生产者写入%d\n", i);
        buffer[count++] = i++;
        // 唤醒消费者
        pthread_cond_signal(&cond);
    }
    // 最后释放锁
    pthread_mutex_unlock (&mutex);
}

 这种做法,可以实现生产者生产完后知道队列满了,然后就消费者消费直到清空,这样子一轮一轮的执行,好处如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2278943.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

每日进步一点点(网安)

今日练习题目是PHP反序列化&#xff0c;也学习一下说明是序列化和反序列化 1.PHP序列化 序列化是指将数据结构或对象转换为可传输或可储存的格式的过程。这通常需要将数据转换为字节流或者其他编码格式&#xff0c;以便在不同系统和应用程序之间进行传输或存储 在PHP中&…

Java-数据结构-二叉树习题(1)

对于二叉树的学习&#xff0c;主要的还是得多多练习~毕竟二叉树属于新的知识&#xff0c;并且也并不是线性结构&#xff0c;再加上经常使用递归的方法解决二叉树的问题&#xff0c;所以代码的具体流程还是无法看到的&#xff0c;只能通过画图想象&#xff0c;所以还是必须多加练…

(二)afsim第三方库编译(qt编译)

注意&#xff1a;源码编译的路径不能有中文否则报错&#xff0c;压缩包必须用官网下载的xz格式解压的才可以&#xff0c;否则sudo ./configure命令找不到 先编译openssl3.1.1软件包&#xff0c;否则编译的qt库将不支持network&#xff0c;相关库的编译(上文&#xff08;一&…

【QT用户登录与界面跳转】

【QT用户登录与界面跳转】 1.前言2. 项目设置3.设计登录界面3.1 login.pro参数3.2 界面设置3.2.1 登录界面3.2.2 串口主界面 4. 实现登录逻辑5.串口界面6.测试功能7.总结 1.前言 在Qt应用程序开发中&#xff0c;实现用户登录及界面跳转功能是构建交互式应用的重要步骤之一。下…

【docker踩坑记录】

docker踩坑记录 踩坑记录(持续更新中.......)docker images 权限问题 踩坑记录(持续更新中…) docker images 权限问题 permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Head "http://%2Fvar%2Frun%2Fdocker.s…

搜维尔科技:Xsens人形机器人解决方案的优势

Xsens 致力于推动人形机器人技术的发展&#xff0c;塑造机器人与人类环境无缝融合的未来&#xff0c;通过创新精确和协作&#xff0c;协助生产和服务&#xff0c;改善人类生活和产业。 Xsens通过人形跟随捕捉详细的人体运动数据&#xff0c;使机器人能够学习类人的动作&#x…

国内微电子(集成电路)领域重点高校的特色与优势

本文旨在梳理国内微电子&#xff08;集成电路&#xff09;领域重点高校的特色与优势&#xff0c;为有志于从事相关领域的学生提供参考。文章将从学科特色、科研实力&#xff08;以ISSCC论文为参考之一&#xff09;、行业认可度等方面进行分析&#xff0c;并强调实验室、导师、研…

leetcode707-设计链表

leetcode 707 思路 本题也是用了虚拟头节点来进行解答&#xff0c;这样的好处是&#xff0c;不管是头节点还是中间的节点都可以当成是中间节点来处理&#xff0c;用同一套方法就可以进行处理&#xff0c;而不用考虑太多的边界条件。 下面题目中最主要的实现就是添加操作addA…

数据结构-栈队列OJ题

文章目录 一、有效的括号二、用队列实现栈三、用栈实现队列四、设计循环队列 一、有效的括号 (链接&#xff1a;ValidParentheses) 这道题用栈这种数据结构解决最好&#xff0c;因为栈有后进先出的性质。简单分析一下这道题&#xff1a;所给字符串不是空的也就是一定至少存在一…

MindAgent:基于大型语言模型的多智能体协作基础设施

2023-09-18 &#xff0c;加州大学洛杉矶分校&#xff08;UCLA&#xff09;、微软研究院、斯坦福大学等机构共同创建的新型基础设施&#xff0c;目的在评估大型语言模型在游戏互动中的规划和协调能力。MindAgent通过CuisineWorld这一新的游戏场景和相关基准&#xff0c;调度多智…

近红外简单ROI分析matlab(NIRS_SPM)

本次笔记主要想验证上篇近红外分析是否正确&#xff0c;因为叠加平均有不同的计算方法&#xff0c;一种是直接将每个通道的5分钟实时长单独进行叠加平均&#xff0c;另一种是将通道划分为1分钟的片段&#xff0c;将感兴趣的通道数据进行对应叠加平均&#xff0c;得到一个总平均…

开发神器之cursor

文章目录 cursor简介主要特点 下载cursor页面的简单介绍切换大模型指定ai学习的文件指定特定的代码喂给ai创建项目框架文件 cursor简介 Cursor 是一款专为开发者设计的智能代码编辑器&#xff0c;集成了先进的 AI 技术&#xff0c;旨在提升编程效率。以下是其主要特点和功能&a…

电脑风扇声音大怎么办? 原因及解决方法

电脑风扇是电脑的重要组件之一&#xff0c;它的作用是为电脑的各个部件提供冷却&#xff0c;防止电脑过热。然而&#xff0c;有时候我们会发现电脑风扇的声音特别大&#xff0c;不仅影响我们的使用体验&#xff0c;也可能是电脑出现了一些问题。那么&#xff0c;电脑风扇声音大…

SpringBoot错误码国际化

先看测试效果&#xff1a; 1. 设置中文 2.设置英文 文件结构 1.中文和英文的错误消息配置 package com.ldj.mybatisflex.common;import lombok.Getter;/*** User: ldj* Date: 2025/1/12* Time: 17:50* Description: 异常消息枚举*/ Getter public enum ExceptionEnum {//…

软考高级5个资格、中级常考4个资格简介及难易程度排序

一、软考高级5个资格 01、网络规划设计师 资格简介&#xff1a;网络规划设计师要求考生具备全面的网络规划、设计、部署和管理能力&#xff1b;该资格考试适合那些在网络规划和设计方面具有较好理论基础和较丰富从业经验的人员参加。 02、系统分析师 资格简介&#xff1a;系统分…

如何通过 Apache Airflow 将数据导入 Elasticsearch

作者&#xff1a;来自 Elastic Andre Luiz 了解如何通过 Apache Airflow 将数据导入 Elasticsearch。 Apache Airflow Apache Airflow 是一个旨在创建、安排&#xff08;schedule&#xff09;和监控工作流的平台。它用于编排 ETL&#xff08;Extract-Transform-Load&#xff0…

STM32 学习笔记【补充】(十)硬件I2C读写MPU6050

该系列为笔者在学习STM32过程&#xff08;主线是江科大的视频&#xff09;中的记录与发散思考。 初学难免有所纰漏、错误&#xff0c;还望大家不吝指正&#xff0c;感谢~ 一、I2C 外设简介 I2C&#xff08;Inter-Integrated Circuit&#xff09;是一种多主多从的串行通信协议…

QT信号槽 笔记

信号与槽就是QT中处理计算机外设响应的一种机制 比如敲击键盘、点击鼠标 // 举例&#xff1a; 代码&#xff1a; connect(ls,SIGNAL(sig_chifanla()),ww,SLOT(slot_quchifan())); connect(ls,SIGNAL(sig_chifanla()),zl,SLOT(slot_quchifan()));connect函数&#xff1a;这是…

【React】插槽渲染机制

目录 通过 children 属性结合条件渲染通过 children 和 slot 属性实现具名插槽通过 props 实现具名插槽 在 React 中&#xff0c;并没有直接类似于 Vue 中的“插槽”机制&#xff08;slot&#xff09;。但是&#xff0c;React 可以通过 props和 children 来实现类似插槽的功能…

openharmony电源管理子系统

电源管理子系统 简介目录使用说明相关仓 简介 电源管理子系统提供如下功能&#xff1a; 重启服务&#xff1a;系统重启和下电。系统电源管理服务&#xff1a;系统电源状态管理和休眠运行锁管理。显示相关的能耗调节&#xff1a;包括根据环境光调节背光亮度&#xff0c;和根…