C语言之pthread_cond_t信号变化探究总结(八十)

2023-10-07 23:10

本文主要是介绍C语言之pthread_cond_t信号变化探究总结(八十),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!

优质专栏:Audio工程师进阶系列原创干货持续更新中……】🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

1.前言

本篇目的: 理解pthread_cond_wait与pthread_cond_timedwait用法区别

函数区别
pthread_cond_wait与pthread_cond_signal函数成对出现,如果没有pthread_cond_signal给它发信号,它死等,等到天荒地老…
pthread_cond_timedwait自己设置超时时间,一旦超过设定时间,自动执行pthread_cond_timedwait函数后边的代码。如果pthread_cond_signal在pthread_cond_timedwait 设置超时时间之前给它发信号,它会收到信号,提前结束等待。
pthread_cond_signal一次只能唤醒一个等待中的线程
pthread_cond_broadcast可以唤醒全部等待中的线程
pthread_mutex_t Linux中用于互斥锁的结构体类型。互斥锁用于保护临界区,确保同时只有一个线程可以访问共享资源。
pthread_cond_t在Linux中,pthread_cond_t是用于线程间同步的条件变量。条件变量用于在线程之间传递信号,帮助线程进行等待和唤醒操作。条件变量通常与互斥锁(pthread_mutex_t)一起使用。当某个线程需要等待某个条件满足时,它会调用pthread_cond_wait函数将自己阻塞,并释放占有的互斥锁。当另一个线程满足了条件并调用了pthread_cond_signal或pthread_cond_broadcast函数发送信号时,等待的线程会被唤醒并重新获取互斥锁,从而继续执行。

2.代码示例

v1.0 pthread_cond_signal和pthread_cond_wait用法

#include <iostream>
#include <thread>
#include <unistd.h>
#include <pthread.h>using namespace std;pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;int main() {std::thread thread = std::thread([&]() {cout << "线程等待信号到来..." << endl;pthread_mutex_lock(&mutex);//1.如果不调用pthread_cond_signal(&cond)函数发信号,永远死等.pthread_cond_wait(&cond, &mutex);cout << "Thread timed wait for 10s." << endl;pthread_mutex_unlock(&mutex);});//1.给pthread_cond_wait和pthread_cond_timedwait发信号(它俩是成对出现的),使其后边的代码可以执行.sleep(1);pthread_cond_signal(&cond);//仅可以唤醒一个线程sleep(2);printf("%s() [%d], cond.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__data))));thread.join();return 0;
}

v2.0 pthread_cond_signal和pthread_cond_timedwait用法

#include <iostream>
#include <thread>
#include <unistd.h>
#include <pthread.h>
#include <sys/time.h>
using namespace std;pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;int main() {//1.给pthread_cond_wait和pthread_cond_timedwait发信号(它俩是成对出现的),使其后边的代码可以执行.std::thread thread = std::thread([&]() {cout << "线程等待信号到来..." << endl;struct timeval now;struct timespec outtime;gettimeofday(&now, NULL);outtime.tv_sec = now.tv_sec + 10;//如果没有等到信号,则超过10s后自动处理.outtime.tv_nsec = now.tv_usec * 1000;pthread_mutex_lock(&mutex);printf("%s() [%d], cond.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__data))));//2.可以设置超时时间,一旦超过设定时间,自动执行pthread_cond_timedwait函数后边的代码,它不受pthread_cond_signal的影响.pthread_cond_timedwait(&cond, &mutex, &outtime);printf("%s() [%d], cond.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__data))));cout << "Thread timed wait for 10s." << endl;pthread_mutex_unlock(&mutex);});sleep(1);pthread_cond_signal(&cond);//仅可以唤醒一个线程sleep(2);thread.join();return 0;
}

v3.0 pthread_cond_broadcast和pthread_cond_wait用法

#include <iostream>
#include <thread>
#include <unistd.h>
#include <pthread.h>using namespace std;pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;int main() {std::thread thread = std::thread([&]() {cout << "线程等待信号到来..." << endl;pthread_mutex_lock(&mutex);//1.如果不调用pthread_cond_signal(&cond)函数发信号,永远死等.pthread_cond_wait(&cond, &mutex);cout << "Thread timed wait for 10s." << endl;pthread_mutex_unlock(&mutex);});//1.给pthread_cond_wait和pthread_cond_timedwait发信号(它俩是成对出现的),使其后边的代码可以执行.sleep(1);pthread_cond_broadcast(&cond);//可以唤醒全部线程sleep(2);printf("%s() [%d], cond.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__data))));thread.join();return 0;
}

v4.0 pthread_cond_broadcast和pthread_cond_timedwait用法

#include <iostream>
#include <thread>
#include <unistd.h>
#include <pthread.h>
#include <sys/time.h>
using namespace std;pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;int main() {//1.给pthread_cond_wait和pthread_cond_timedwait发信号(它俩是成对出现的),使其后边的代码可以执行.std::thread thread = std::thread([&]() {cout << "线程等待信号到来..." << endl;struct timeval now;struct timespec outtime;gettimeofday(&now, NULL);outtime.tv_sec = now.tv_sec + 10;//如果没有等到信号,则超过10s后自动处理.outtime.tv_nsec = now.tv_usec * 1000;pthread_mutex_lock(&mutex);printf("%s() [%d], cond.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__data))));//2.可以设置超时时间,一旦超过设定时间,自动执行pthread_cond_timedwait函数后边的代码,它不受pthread_cond_signal的影响.pthread_cond_timedwait(&cond, &mutex, &outtime);printf("%s() [%d], cond.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__data))));cout << "Thread timed wait for 10s." << endl;pthread_mutex_unlock(&mutex);});sleep(1);pthread_cond_broadcast(&cond);//可以唤醒全部线程sleep(2);thread.join();return 0;
}

v5.0 pthread_cond_wait: 观察pthread_cond_t和pthread_mutex_t结构体中变量:__data、__size、__align变化

pthread_cond_signal和pthread_cond_wait用法

#include <iostream>
#include <thread>
#include <unistd.h>
#include <pthread.h>using namespace std;pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;int main() {std::thread thread = std::thread([&]() {cout << "线程等待信号到来..." << endl;printf("%s() [%d], cond.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__data))));pthread_mutex_lock(&mutex);//1.如果不调用pthread_cond_signal(&cond)函数发信号,永远死等.pthread_cond_wait(&cond, &mutex);printf("%s() [%d], cond.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__data))));cout << "Thread timed wait for 10s." << endl;pthread_mutex_unlock(&mutex);});//1.给pthread_cond_wait和pthread_cond_timedwait发信号(它俩是成对出现的),使其后边的代码可以执行.sleep(1);printf("%s() [%d], cond.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__data))));printf("%s() [%d], cond.__data = %d\n",__FUNCTION__,__LINE__,*(reinterpret_cast<int*>(&(cond.__data))));printf("%s() [%d], cond.__size = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__size))));printf("%s() [%d], cond.__align = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__align))));printf("%s() [%d], mutex.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(mutex.__data))));printf("%s() [%d], mutex.__size = %d\n",__FUNCTION__,__LINE__,*((int*)(&(mutex.__size))));printf("%s() [%d], mutex.__align = %d\n",__FUNCTION__,__LINE__,*((int*)(&(mutex.__align))));//pthread_cond_signal(&cond);//仅可以唤醒一个线程pthread_cond_broadcast(&cond);//可以唤醒全部线程printf("%s() [%d], cond.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__data))));printf("%s() [%d], cond.__size = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__size))));printf("%s() [%d], cond.__align = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__align))));printf("%s() [%d], mutex.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(mutex.__data))));printf("%s() [%d], mutex.__size = %d\n",__FUNCTION__,__LINE__,*((int*)(&(mutex.__size))));printf("%s() [%d], mutex.__align = %d\n",__FUNCTION__,__LINE__,*((int*)(&(mutex.__align))));sleep(2);printf("%s() [%d], cond.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__data))));thread.join();return 0;
}

打印:

线程等待信号到来...
operator()() [16], cond.__data = 0
main() [27], cond.__data = 2
main() [28], cond.__data = 2
main() [30], cond.__size = 2
main() [31], cond.__align = 2
main() [33], mutex.__data = 0
main() [34], mutex.__size = 0
main() [35], mutex.__align = 0
main() [40], cond.__data = 3
main() [41], cond.__size = 3
main() [42], cond.__align = 3
main() [44], mutex.__data = 0
main() [45], mutex.__size = 0
main() [46], mutex.__align = 0
operator()() [20], cond.__data = 3
Thread timed wait for 10s.
main() [49], cond.__data = 3

总结:
在进入线程后,信号没来到之前 cond.__data=0;
当进入main进程时,cond.__data=2;
当pthread_cond_signal(&cond)发送信号后,cond.__data=3,然后线程中的pthread_cond_wait(&cond, &mutex)收到cond.__data=3的信号,
立即释放互斥锁,解除阻塞,程序向下运行,到main函数结束。

v6.0 观察pthread_cond_timedwait:pthread_cond_t和pthread_mutex_t结构体中变量:__data、__size、__align变化

pthread_cond_signal和pthread_cond_timedwait用法

#include <iostream>
#include <thread>
#include <unistd.h>
#include <pthread.h>
#include <sys/time.h>
using namespace std;pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;int main() {//1.给pthread_cond_wait和pthread_cond_timedwait发信号(它俩是成对出现的),使其后边的代码可以执行.std::thread thread = std::thread([&]() {cout << "线程等待信号到来..." << endl;struct timeval now;struct timespec outtime;gettimeofday(&now, NULL);outtime.tv_sec = now.tv_sec + 10;//如果没有等到信号,则超过10s后自动处理.outtime.tv_nsec = now.tv_usec * 1000;pthread_mutex_lock(&mutex);printf("%s() [%d], cond.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__data))));//2.可以设置超时时间,一旦超过设定时间,自动执行pthread_cond_timedwait函数后边的代码,它不受pthread_cond_signal的影响.pthread_cond_timedwait(&cond, &mutex, &outtime);printf("%s() [%d], cond.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__data))));cout << "Thread timed wait for 10s." << endl;pthread_mutex_unlock(&mutex);});sleep(1);printf("%s() [%d], cond.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__data))));printf("%s() [%d], cond.__data = %d\n",__FUNCTION__,__LINE__,*(reinterpret_cast<int*>(&(cond.__data))));printf("%s() [%d], cond.__size = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__size))));printf("%s() [%d], cond.__align = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__align))));printf("%s() [%d], mutex.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(mutex.__data))));printf("%s() [%d], mutex.__size = %d\n",__FUNCTION__,__LINE__,*((int*)(&(mutex.__size))));printf("%s() [%d], mutex.__align = %d\n",__FUNCTION__,__LINE__,*((int*)(&(mutex.__align))));//pthread_cond_signal(&cond);//仅可以唤醒一个线程pthread_cond_broadcast(&cond);//可以唤醒全部线程printf("%s() [%d], cond.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__data))));printf("%s() [%d], cond.__size = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__size))));printf("%s() [%d], cond.__align = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__align))));printf("%s() [%d], mutex.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(mutex.__data))));printf("%s() [%d], mutex.__size = %d\n",__FUNCTION__,__LINE__,*((int*)(&(mutex.__size))));printf("%s() [%d], mutex.__align = %d\n",__FUNCTION__,__LINE__,*((int*)(&(mutex.__align))));sleep(2);printf("%s() [%d], cond.__data = %d\n",__FUNCTION__,__LINE__,*((int*)(&(cond.__data))));thread.join();return 0;
}

打印

线程等待信号到来...
operator()() [23], cond.__data = 0
main() [33], cond.__data = 2
main() [34], cond.__data = 2
main() [37], cond.__size = 2
main() [38], cond.__align = 2
main() [40], mutex.__data = 0
main() [41], mutex.__size = 0
main() [42], mutex.__align = 0
main() [46], cond.__data = 3
main() [47], cond.__size = 3
main() [48], cond.__align = 3
main() [50], mutex.__data = 0
main() [51], mutex.__size = 0
main() [52], mutex.__align = 0
operator()() [26], cond.__data = 3
Thread timed wait for 10s.
main() [55], cond.__data = 3

总结:
在进入线程后,信号没来到之前 cond.__data=0;
当进入main进程时,cond.__data=2;
当pthread_cond_signal(&cond)发送信号后,cond.__data=3,然后线程中的pthread_cond_wait(&cond, &mutex)收到cond.__data=3的信号,
立即释放互斥锁,解除阻塞,程序向下运行,到main函数结束。

3.总结

所以不管是pthread_cond_signal、pthread_cond_broadcast发送信号给pthread_cond_wait,还是pthread_cond_timedwait,最终信号发生变化的pthread_cond_t是的结构体变量__data字段,是它发生的变化,解除线程的阻塞状态。

这篇关于C语言之pthread_cond_t信号变化探究总结(八十)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/161043

相关文章

Rust格式化输出方式总结

《Rust格式化输出方式总结》Rust提供了强大的格式化输出功能,通过std::fmt模块和相关的宏来实现,主要的输出宏包括println!和format!,它们支持多种格式化占位符,如{}、{:?}... 目录Rust格式化输出方式基本的格式化输出格式化占位符Format 特性总结Rust格式化输出方式

使用Go语言开发一个命令行文件管理工具

《使用Go语言开发一个命令行文件管理工具》这篇文章主要为大家详细介绍了如何使用Go语言开发一款命令行文件管理工具,支持批量重命名,删除,创建,移动文件,需要的小伙伴可以了解下... 目录一、工具功能一览二、核心代码解析1. 主程序结构2. 批量重命名3. 批量删除4. 创建文件/目录5. 批量移动三、如何安

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

Go语言中三种容器类型的数据结构详解

《Go语言中三种容器类型的数据结构详解》在Go语言中,有三种主要的容器类型用于存储和操作集合数据:本文主要介绍三者的使用与区别,感兴趣的小伙伴可以跟随小编一起学习一下... 目录基本概念1. 数组(Array)2. 切片(Slice)3. 映射(Map)对比总结注意事项基本概念在 Go 语言中,有三种主要

使用C++将处理后的信号保存为PNG和TIFF格式

《使用C++将处理后的信号保存为PNG和TIFF格式》在信号处理领域,我们常常需要将处理结果以图像的形式保存下来,方便后续分析和展示,C++提供了多种库来处理图像数据,本文将介绍如何使用stb_ima... 目录1. PNG格式保存使用stb_imagephp_write库1.1 安装和包含库1.2 代码解

C语言中自动与强制转换全解析

《C语言中自动与强制转换全解析》在编写C程序时,类型转换是确保数据正确性和一致性的关键环节,无论是隐式转换还是显式转换,都各有特点和应用场景,本文将详细探讨C语言中的类型转换机制,帮助您更好地理解并在... 目录类型转换的重要性自动类型转换(隐式转换)强制类型转换(显式转换)常见错误与注意事项总结与建议类型

Python中连接不同数据库的方法总结

《Python中连接不同数据库的方法总结》在数据驱动的现代应用开发中,Python凭借其丰富的库和强大的生态系统,成为连接各种数据库的理想编程语言,下面我们就来看看如何使用Python实现连接常用的几... 目录一、连接mysql数据库二、连接PostgreSQL数据库三、连接SQLite数据库四、连接Mo

Go语言利用泛型封装常见的Map操作

《Go语言利用泛型封装常见的Map操作》Go语言在1.18版本中引入了泛型,这是Go语言发展的一个重要里程碑,它极大地增强了语言的表达能力和灵活性,本文将通过泛型实现封装常见的Map操作,感... 目录什么是泛型泛型解决了什么问题Go泛型基于泛型的常见Map操作代码合集总结什么是泛型泛型是一种编程范式,允

Git提交代码详细流程及问题总结

《Git提交代码详细流程及问题总结》:本文主要介绍Git的三大分区,分别是工作区、暂存区和版本库,并详细描述了提交、推送、拉取代码和合并分支的流程,文中通过代码介绍的非常详解,需要的朋友可以参考下... 目录1.git 三大分区2.Git提交、推送、拉取代码、合并分支详细流程3.问题总结4.git push

Android kotlin语言实现删除文件的解决方案

《Androidkotlin语言实现删除文件的解决方案》:本文主要介绍Androidkotlin语言实现删除文件的解决方案,在项目开发过程中,尤其是需要跨平台协作的项目,那么删除用户指定的文件的... 目录一、前言二、适用环境三、模板内容1.权限申请2.Activity中的模板一、前言在项目开发过程中,尤