linux进阶52——pthread_cond_t

2023-11-19

1. 概念

  • 条件变量是线程可用的另一种同步机制
  • 条件变量给多个线程提供了一个会合的场所
  • 条件变量与互斥量一起使用时,允许线程以无竞争的方式等待特定的条件发生
  • 条件变量是线程中的东西,就是等待某一条件的发生,和信号一样

2. 使用场景

  • 条件变量要与互斥量一起使用,条件本身是由互斥量保护的。线程在改变条件状态之前必须首先锁住互斥量
  • 其他线程在获得互斥量之前不会察觉到这种改变,因为互斥量必须在锁定以后才能计算条件

3. 数据类型

  • pthread_cond_t

4. 条件变量初始化与释放

①静态初始化

  • 直接把pthread_cond_t定义的条件变量设置为常量PTHREAD_COND_INITIALIZER
  • 静态初始化条件变量只能拥有默认的条件变量属性,不能设置其他条件变量属性
pthread_cond_t cond;
cond=PTHREAD_COND_INITIALIZER;
 
//或者
pthread_cond_t *cond=(pthread_cond_t *)malloc(sizeof(pthread_cond_t));
*cond=PTHREAD_COND_INITIALIZER;

②动态初始化

  • 静态初始化条件变量只能拥有默认条件变量属性,我们可以通过pthread_mutex_init函数来动态初始化条件变量,并且可以在初始化时选择设置条件变量的属性
#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);
 
//返回值:成功返回0;失败返回错误编号

pthread_cond_init:

  • 功能:对条件变量初始化
  • 参数:
  • 参数1: 需要初始化的条件变量
  • 参数2:初始化时条件变量的属性。如果使用默认属性,此处填NULL

pthread_cond_destroy:

  • 功能:对条件变量反初始化(在条件变量释放内存之前)
  • 参数:条件变量
  • 备注(重点):此函数只是反初始化互斥量,并没有释放内存空间,如果互斥量是通过malloc等函数申请的,那么需要在free掉互斥量之前调用pthread_mutex_destroy函数
pthread_cond_t cond;
pthread_cond_init(&cond,NULL);
 
/*do something*/
 
pthread_cond_destroy(&cond);
pthread_cond_t * cond=(pthread_cond_t *)malloc(sizeof(pthread_cond_t));
pthread_cond_init(cond,NULL);
 
/*do something*/
 
pthread_cond_destroy(cond);
free(cond);

5. 等待条件变量

#include <pthread.h>
int pthread_cond_wait(pthread_cond_t* restrict cond,pthread_mutex_t* restrict mutex);
int pthread_cond_timedwait(pthread_cond_t* cond,pthread_mutex_t* restrict mutex,const struct timespec* restrict tsptr);
 
//返回值:成功返回0;失败返回错误编号
  •  这两个函数调用成功返回时,线程需要重新计算条件,因为另一个线程可能已经在运行并改变了条件

pthread_cond_wait

  • 注意:等待条件变量变为真

  • 如何使用:参数mutex互斥量提前锁定,然后该互斥量对条件进行保护,等待参数1cond条件变量变为真。在等待条件变量变为真的过程中,此函数一直处于阻塞状态。但是处于阻塞状态的时候,mutex互斥量被解锁(因为其他线程需要使用到这个锁来使条件变量变为真)

  • 当pthread_cond_wait函数返回时,互斥量再次被锁住

pthread_cond_timedwait

  • pthread_cond_timedwait函数与pthread_cond_wait函数功能相同。不过多了一个超时参数。超时值指定了我们愿意等待多长时间,它是通过timespec结构体表示的
  • 如果超时到期之后,条件还是没有出现,此函数将重新获取互斥量,然后返回错误ETIMEOUT
  • 注意:这个时间值是一个绝对数而不是相对数。例如,假设愿意等待3分钟,那么不是把3分钟转换为timespec结构体,而是需要把当前时间加上3分钟再转换成timespec结构

下面定义了一个得到超时值的绝对时间获取函数:

  • 可以使用clock_gettime函数获取timespec结构表示的当前时间。但是目前并不是所有的平台都支持这个函数。因此,可以使用gettimeofday获取timeval结构表示的当前时间,然后把这个时间转换为timespec结构
#include <sys/time.h>
#include <stdlib.h>
 
void maketimeout(struct timespec *tsp, long minutes)
{
	struct timeval now;
 
	/* get the current time */
	gettimeofday(&now, NULL);
	tsp->tv_sec = now.tv_sec;
	tsp->tv_nsec = now.tv_usec * 1000; /* usec to nsec */
	/* add the offset to get timeout value */
	tsp->tv_sec += minutes * 60;
}

6. 条件变量信号发送

#include <pthread.h>
int pthread_cond_signal(pthread_cond_t* cond);
int pthread_cond_broadcast(pthread_cond_t* cond);
 
//返回值:成功返回0;失败返回错误编号
  • 这两个函数用于通知线程条件变量已经满足条件(变为真)。在调用这两个函数时,是在给线程或者条件发信号
  • 必须注意:一定要在改变条件状态以后再给线程发信号
  • pthread_cond_signal函数:至少能唤醒一个等待该条件的线程
  • pthread_cond_broad函数:则唤醒等待该条件的所有线程

7. 示例

#include <pthread.h>
 
struct msg {
	struct msg *m_next;
	/* ... more stuff here ... */
};
 
struct msg *workq;
pthread_cond_t qready = PTHREAD_COND_INITIALIZER;
pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER;
 
void  process_msg(void)
{
	struct msg *mp;
 
	for (;;) {
		pthread_mutex_lock(&qlock);
		while (workq == NULL)
			pthread_cond_wait(&qready, &qlock);
		mp = workq;
		workq = mp->m_next;
		pthread_mutex_unlock(&qlock);
		/* now process the message mp */
	}
}
 
void  enqueue_msg(struct msg *mp)
{
	pthread_mutex_lock(&qlock);
	mp->m_next = workq;
	workq = mp;
	pthread_mutex_unlock(&qlock);
	pthread_cond_signal(&qready);
}

8. 案例

 

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h> 
#include <strings.h>
 
#define BUFFSIZE 2
struct prodcons
{
    char buff[BUFFSIZE];
    int write_index;
    int read_index;
    pthread_cond_t notempty;
    pthread_cond_t notfull;
    pthread_mutex_t lock;
};
 
void  init(struct prodcons *pro);
void* producer_func(void* arg);
void* customer_func(void* arg);
void  put(struct prodcons *pro,int data);
int   get(struct prodcons *pro);
 
int main()
{
    pthread_t producer,customer;
    struct prodcons pro;
 
    init(&pro);
    
    if(pthread_create(&producer,NULL,producer_func,&pro)!=0){
        perror("pthread_create");
        exit(EXIT_FAILURE);
    }
    if(pthread_create(&customer,NULL,customer_func,&pro)!=0){
        perror("pthread_create");
        exit(EXIT_FAILURE);
    }
 
    if(pthread_join(producer,NULL)!=0){
        perror("pthread_join");
        exit(EXIT_FAILURE);
    }
    if(pthread_join(customer,NULL)!=0){
        perror("pthread_join");
        exit(EXIT_FAILURE);
    }
 
    exit(0);
}
 
void init(struct prodcons *pro)
{
    bzero(pro->buff,sizeof(pro->buff));
    pro->write_index=0;
    pro->read_index=0;
    if((pthread_cond_init(&pro->notempty,NULL)!=0)
        ||(pthread_cond_init(&pro->notfull,NULL)!=0)
        ||(pthread_mutex_init(&pro->lock,NULL)!=0)){
        perror("init");
        exit(EXIT_FAILURE);
    }
}
 
void* producer_func(void* arg)
{
    int i;
    for(i=1;i<=5;++i)
    {
        printf("producer sleep 1 second to produce..\n");
        sleep(1);
        printf("put %d to produce\n",i);
        put(arg,i);
    }
    for(i=6;i<=10;++i)
    {
        printf("producer sleep 3 second to produce..\n");
        sleep(3);
        printf("produce:put %d\n",i);
        put(arg,i);
    }
    put(arg, -1);
    printf("producer exit\n");
    pthread_exit(0);
}
 
void* customer_func(void* arg)
{
    int data;
    while(1)
    {
        printf("customer wait 2 second to consumption.\n");
        sleep(2);
        data=get(arg);
        printf("customer:get %d\n",data);
        if(data==-1)
            break;
    }
    printf("customer exit\n");
    pthread_exit(0);
}
 
void put(struct prodcons *pro,int data)
{
    pthread_mutex_lock(&pro->lock);
    //如果满了,等到非满条件变量产生
    while(((pro->write_index+1)%BUFFSIZE) == pro->read_index)
    {
        printf("producer is full,wait not full");
        pthread_cond_wait(&pro->notfull,&pro->lock);
    }
    pro->buff[pro->write_index]=data;
    pro->write_index++;
    if(pro->write_index>=BUFFSIZE)
        pro->write_index=0;
    pthread_cond_signal(&pro->notempty);
    pthread_mutex_unlock(&pro->lock);
}
 
int   get(struct prodcons *pro)
{
    int data;
    pthread_mutex_lock(&pro->lock);
    //如果空了,则等待非空
    while(pro->write_index==pro->read_index)
    {
        printf("customer is empty,wait not empty\n");
        pthread_cond_wait(&pro->notempty,&pro->lock);
    }
    data=pro->buff[pro->read_index];
    pro->read_index++;
    if(pro->read_index>=BUFFSIZE)
        pro->read_index=0;
    pthread_cond_signal(&pro->notfull);
    pthread_mutex_unlock(&pro->lock);
    return data;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux进阶52——pthread_cond_t 的相关文章

  • 如何通过替换为空页映射来取消映射 mmap 文件

    Linux 用户空间有没有办法用空页面 映射自 dev null 或者可能是一个空页面 重复映射到从文件映射的页面的顶部 对于上下文 我想找到这个 JDK bug 的修复 https bugs openjdk java net browse
  • 从 csv 文件中删除特定列,保持输出上的相同结构[重复]

    这个问题在这里已经有答案了 我想删除第 3 列并在输出文件中保留相同的结构 输入文件 12 10 10 10 10 1 12 23 1 45 6 7 11 2 33 45 1 2 1 2 34 5 6 I tried awk F 3 fil
  • 如何禁用 GNOME 桌面屏幕锁定? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 如何阻止 GNOME 桌面在几分钟空闲时间后锁定屏幕 我已经尝试过官方手册了在红帽 https access redhat com doc
  • 如何根据 HTTP 请求使用 Python 和 Flask 执行 shell 命令并流输出?

    下列的这个帖子 https stackoverflow com questions 15092961 how to continuously display python output in a webpage 我能够tail f网页的日志
  • sendfile64 只复制约2GB

    我需要使用 sendfile64 复制大约 16GB 的文件 到目前为止我所取得的成就是 include
  • 在哪里可以找到并安装 pygame 的依赖项?

    我对 Linux 比较陌生 正在尝试安装 python 的 pygame 开发环境 当我运行 setup py 时 它说我需要安装以下依赖项 我找到并安装了其中之一 SDL 然而 其他人则更加难以捉摸 Hunting dependencie
  • fopen 不返回

    我在 C 程序中使用 fopen 以只读模式 r 打开文件 但就我而言 我观察到 fopen 调用没有返回 它不返回 NULL 或有效指针 执行在 fopen 调用时被阻止 文件补丁绝对正确 我已经验证过 并且不存在与权限相关的问题 任何人
  • 尝试安装 LESS 时出现“请尝试以 root/管理员身份再次运行此命令”错误

    我正在尝试在我的计算机上安装 LESS 并且已经安装了节点 但是 当我输入 node install g less 时 出现以下错误 并且不知道该怎么办 FPaulMAC bin paul npm install g less npm ER
  • 无法使用 wget 在 CentOS 机器上安装 oracle jdk

    我想在CentOS上安装oracle java jdk 8 我无法安装 java jdk 因为当我尝试使用命令安装 java jdk 时 root ADARSH PROD1 wget no cookies no check certific
  • 两种情况或 if 哪个更快? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我必须制作一个 非常 轻的脚本 它将接受用户的选项并调用脚本中的函数来执行一些任务 现在我可以使用 IF 和 CASE 选项 但我想知道两
  • 如何在Linux内核源代码中打印IP地址或MAC地址

    我必须通过修改 Linux 内核源代码来稍微改变 TCP 拥塞控制算法 但为了检查结果是否正确 我需要记录 MAC 或 IP 地址信息 我使用 PRINTK 函数来打印内核消息 但我感觉很难打印出主机的MAC IP地址 printk pM
  • PHP 从命令行启动 gui 程序,但 apache 不启动

    首先 我阅读了有类似问题的人的一些帖子 但所有答案都没有超出导出 DISPLAY 0 0 和 xauth cookies 这是我的问题 提前感谢您的宝贵时间 我开发了一个小库 它使用 OpenGL 和 GLSL 渲染货架 过去几天我将它包装
  • Linux 内核标识符中前导和尾随下划线的含义是什么?

    我不断遇到一些小约定 比如 KERNEL Are the 在这种情况下 是内核开发人员使用的命名约定 还是以这种方式命名宏的语法特定原因 整个代码中有很多这样的例子 例如 某些函数和变量以 甚至 这有什么具体原因吗 它似乎被广泛使用 我只需
  • CentOS:无法安装 Chromium 浏览器

    我正在尝试在 centOS 6 i 中安装 chromium 以 root 用户身份运行以下命令 cd etc yum repos d wget http repos fedorapeople org repos spot chromium
  • NPTL 和 POSIX 线程有什么区别?

    NPTL 和 POSIX 线程之间的基本区别是什么 这两者是如何演变的 POSIX 线程 pthread 不是一个实现 它是几个函数的 API 规范 纸上的标准 英文 其名称以pthread 以及定义在
  • PHP 无法打开流:是一个目录

    非常简单的 PHP 脚本 我在我亲自设置的 Ubuntu Web 服务器上的 EE 模板中运行 我知道这与权限有关 并且我已经将我尝试写入的目录的所有者更改为 Apache 用户 我得到的错误是 遇到 PHP 错误 严重性 警告 消息 fi
  • jq中如何分组?

    这是 json 文档 name bucket1 clusterName cluster1 name bucket2 clusterName cluster1 name bucket3 clusterName cluster2 name bu
  • 我的线程图像生成应用程序如何将其数据传输到 GUI?

    Mandelbrot 生成器的缓慢多精度实现 线程化 使用 POSIX 线程 Gtk 图形用户界面 我有点失落了 这是我第一次尝试编写线程程序 我实际上并没有尝试转换它的单线程版本 只是尝试实现基本框架 到目前为止它是如何工作的简要描述 M
  • 查找哪个程序运行另一个程序

    我有一个 NAS 运行在 Redhat Linux 的有限版本上 我按照指示破解了它 这样我就可以访问 shell 这很有帮助 我还做了一些修改 其他人也做过修改 除了一个问题之外 它们似乎都工作得很好 不知何故 每隔 22 天 系统就会关
  • 如何更改 Apache 服务器的根目录? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 如何更改 Apache 服务器的文档根目录 我基本上想要localhost从 来 users spencer projects目录而不是

随机推荐

  • 计算机网络-协议栈分层

    1 划分网络层次的优缺点 优点 1 开发人员可以只关注整个结构中的某一层 2 可以很容易用新的实现替换原有层次中的实现 3 可以降低层与层之间的依赖 4 有利于标准化 5 利于各层逻辑的复用 缺点 1 一层可能冗余较低层的功能 例如许多协议
  • 【云原生

    本期文章是K8s第3篇 主要是实战Kubectl创建Deployment部署应用 通过本期文章 我们将学习创建在 Kubernetes 集群上运行应用程序的 Deployment 所需的最常见的 Kubectl 命令 在前期的文章中 已经介
  • 优惠券叠加规则、优惠分摊介绍

    本文主要介绍优惠券的叠加规则 下单结算时的优惠券分摊及优惠券核销细节 同时也会将上面提到的各种优惠券 以某宝下单的例子来讲解内容 对于优惠券的使用从场景不同可以分为 线上使用和线下使用 其实严格的讲两个方式最终的目的和结果都一样 1 线上使
  • OpenWRT命令

    系统信息 arch 显示体系结构 uname m 显示当前硬件平台的类型 uname r 显示使用的内核版本 dmidecode q 显示硬件系统组件 SMBIOS DMI hdparm i dev hda 显示硬盘特征 hdparm tT
  • Python循环结构

    while循环 如果不使用循环语句 就只能用下面的方法逐个输出单个字符 使用循环结构就可以更方便地遍历 username EMT print username 0 print username 1 print username 2 用下面的
  • windows下使用CMake构建工程:cmake-gui+Visual Studio

    文件结构 在工程目录下构建目录src thirdparty build src 存放自己写的源代码文件 thirdparty 存放使用的第三方库 build 存放编译时生成的文件 因为很多很杂乱 所以单独目录存放 保持项目文件夹整洁 在bu
  • 核方法、核密度估计与核函数

    核方法 核密度估计与核函数 核方法 Kernel Methods 是一类常用于机器学习和统计学中的非参数方法 主要用于特征转换和模式识别 核方法通过将数据映射到高维特征空间 使得线性不可分的问题在高维空间中变得线性可分 其中 核函数 Ker
  • 未来展望——学习规划

    不知不觉就来到了研二 找工作和科研两座大山压在身上 我的专业是机械设计及理论 主要研究的方向是新能源汽车电驱动系统设计 平时主要的工作就是先在Matlab Simulink里搭建出PMSM的控制模型 观测器模型等 再将其转化为C代码烧录到D
  • 什么是GPT?初学者如何使用GPT?GPT入门学习

    灵魂发问 GPT科研中没有那么神 GPT账号不能轻松使用 GPT怎样才融合到我的科研中 别人用的非常酷 为什么我用的不行 让GPT成为您的科研加速器 GPT对于每个科研人员已经成为不可或缺的辅助工具 不同的研究领域和项目具有不同的需求 如在
  • tp-wr886n虚拟服务器在哪,新版TP-LINK TL-WR886N默认登录地址是多少?【图解】

    新版TP LINK TL WR886N默认登录地址是多少 问 最近刚买的普联TP LINK新款无线路由器 请问tplink TL WR886N默认登录地址是多少 想要登录这台TL WR886N不知道管理IP地址如何登录呢 答 TP LINK
  • iOS进阶_kvc使用注意事项

    细节1 我们在项目中使用kvc 在设置model属性的时候 注意尽量不要使用基本数据类型 实例 数据模拟 注意age是null类型的 Person h import
  • robotframework安装使用

    一 Robot Framework 介绍 Robot Framework 是一款基于 Python 的功能自动化测试框架 它具备良好的可扩展性 支持关键字驱动 可以同时测试多种类型的客户端或者接口 可以进行分布式测试执行 主要用于轮次很多的
  • 解决问题方法汇总:ROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysq

    var lib mysql mysql sock 这个目录是my cnf中配置的 连接localhost通常通过一个Unix域套接字文件进行 即这个mysql sock文件 如果套接字文件被删除了 本地客户就不能连接 systemctl s
  • el-upload上传阿里云(oss上传)

    oss上传 在你的项目安装oss npm install ali oss save 初始化oss 配置文件 新建一个js文件 内容如下 代表你所申请的参数 问运维要 let OSS require ali oss export let cl
  • Oracle函数集锦

    一 case when then 用法 case具有两种格式 简单case函数和case搜索函数 简单case函数 case sex when 1 then 男 when 2 then 女 else 其他 end case搜索函数 case
  • OpenGL GLFW入门篇 - 画矩形2

    上一篇介绍了如何渲染矩形 这一篇介绍如何将叠加的部分透明显示 效果图 主体代码 void DrawRectangle void GLfloat xl yt xr yb w h glPushMatrix glLoadIdentity glTr
  • [vue3]用element封装一个抽屉组件

    需求 因为抽屉组件在后台管理系统是非常常见的 那么封装起来怎么样 可以传入标题 size 提交按钮的文字 传入部分即便超出范围也不会挤掉下面的按钮 会出现滚动条 如图
  • 文件目录和目录文件的作用区别和联系 & C语言文件相关操作 FILE用法

    一 文件目录和目录文件的作用区别和联系 1 他们各自的概念和联系 文件目录 把所有的FCB组织在一起 就构成了文件目录 即文件控制块的有序集合 FCB 为了能对一个文件进行正确的存取 操作系统必须为文件设置用于描述和控制文件的数据结构 称之
  • setlocale()/_wsetlocale()函数的使用

    在C运行库提供的多字节字符 宽字符转换函数 mbstowcs wcstombs 中 需要用到全局变量locale locale encoding 以指定多字节字符的编码类型 1 功能 用来定义全局变量 locale locale encod
  • linux进阶52——pthread_cond_t

    1 概念 条件变量是线程可用的另一种同步机制 条件变量给多个线程提供了一个会合的场所 条件变量与互斥量一起使用时 允许线程以无竞争的方式等待特定的条件发生 条件变量是线程中的东西 就是等待某一条件的发生 和信号一样 2 使用场景 条件变量要