linux平台,对线程等待和唤醒操作的封装(pthread_cond_timedwait 用法详解)
前言 linux平台下,线程等待和唤醒操作是很常见的,但是平台函数不易使用;笔者对此操作做了封装,使之更易于使用。
线程等待和唤醒函数比较
平台提供了线程等待相关函数,这些函数之间用法也有些差异:
| sleep | 线程等待,等待期间线程无法唤醒。 |
| pthread_cond_wait | 线程等待信号触发,如果没有信号触发,无限期等待下去。 |
| pthread_cond_timedwait | 线程等待一定的时间,如果超时或有信号触发,线程唤醒。 |
通过上表,可以看出pthread_cond_timedwait函数是最为灵活,使用也最为广泛。sleep的缺陷是当有紧急事件到达时,线程无法及时唤醒。pthread_cond_wait缺陷是:必须借助别的线程触发信号,否则线程自身无法唤醒,如果使用函数,线程无法处理定时任务。
一般情况下,线程要做的工作可能有:定期处理某个事物;无事可做时,线程挂起;有事可做时,立即唤醒工作。要完成上面所述的功能,必须用pthread_cond_timedwait函数,本文介绍的就是对该函数封装。
线程唤醒操作还涉及互斥量pthread_mutex_t,感觉与我们理解的等待和唤醒操作无关;此函数的引入,增加了理解难度。本文封装完全屏蔽了此概念。
函数定义如下
//函数涉及的变量
typedef struct ThreadSignal_T
{
BOOL relativeTimespan; //是否采用相对时间 pthread_cond_t cond;
pthread_mutex_t mutex; pthread_condattr_t cattr; } ThreadSignal; //初始化
void ThreadSignal_Init(ThreadSignal *signal,BOOL relativeTimespan);
//关闭
void ThreadSignal_Close(ThreadSignal *signal); //等待n毫秒
void ThreadSignal_Wait(ThreadSignal *signal, int ms);
//唤醒线程
void ThreadSignal_Signal(ThreadSignal *signal);
上述函数定义非常直观,利于理解。但是平台提供的函数,就不是那么直观。我把上述函数的实现一一列出来。
1)ThreadSignal_Init
void ThreadSignal_Init(ThreadSignal *signal, BOOL relativeTimespan)
{
//relativeTimespan 是不是采用相对时间等待。参见函数 ThreadSignal_Wait
signal->relativeTimespan = relativeTimespan; pthread_mutex_init(&signal->mutex, NULL); if (relativeTimespan)
{
//如果采用相对时间等待,需要额外的处理。
//采用相对时间等待。可以避免:因系统调整时间,导致等待时间出现错误。
int ret = pthread_condattr_init(&signal->cattr);
ret = pthread_condattr_setclock(&signal->cattr, CLOCK_MONOTONIC); ret = pthread_cond_init(&signal->cond, &signal->cattr);
}
else
{
pthread_cond_init(&signal->cond, NULL);
}
}
2) ThreadSignal_Close
void ThreadSignal_Close(ThreadSignal *signal)
{
if (signal->relativeTimespan)
{
pthread_condattr_destroy(&(signal->cattr));
} pthread_mutex_destroy(&signal->mutex);
pthread_cond_destroy(&signal->cond);
}
3) ThreadSignal_Wait
void ThreadSignal_Wait(ThreadSignal *signal, int ms)
{
pthread_mutex_lock(&signal->mutex); if (signal->relativeTimespan)
{
//获取时间
struct timespec outtime;
clock_gettime(CLOCK_MONOTONIC, &outtime);
//ms为毫秒,换算成秒
outtime.tv_sec += ms/; //在outtime的基础上,增加ms毫秒
//outtime.tv_nsec为纳秒,1微秒=1000纳秒
//tv_nsec此值再加上剩余的毫秒数 ms%1000,有可能超过1秒。需要特殊处理
uint64_t us = outtime.tv_nsec/ + * (ms % ); //微秒
//us的值有可能超过1秒,
outtime.tv_sec += us / ; us = us % ;
outtime.tv_nsec = us * ;//换算成纳秒 int ret = pthread_cond_timedwait(&signal->cond, &signal->mutex, &outtime);
}
else
{
struct timeval now;
gettimeofday(&now, NULL); //在now基础上,增加ms毫秒
struct timespec outtime;
outtime.tv_sec = now.tv_sec + ms / ; //us的值有可能超过1秒
uint64_t us = now.tv_usec + * (ms % );
outtime.tv_sec += us / ; us = us % ;
outtime.tv_nsec = us * ; int ret = pthread_cond_timedwait(&signal->cond, &signal->mutex, &outtime);
}
pthread_mutex_unlock(&signal->mutex);
}
上述函数处理起来有点啰嗦,有些读者可能认为这是多此一举,其实不然。 struct timespec outtime;结构中有两个值:tv_sec ,tv_usec 。分别是秒和纳秒。等待一段时间就是:在这两个值上增加一定的数值。
tv_usec 此值有范围限制的,就是不能超过1秒暨1000000000纳秒。如果超出1秒,就要在tv_sec 此值增加一秒;tv_usec 减去一秒。笔者是在实践中发现此问题的,不是无中生有。如果tv_usec 此值溢出,调用pthread_cond_timedwait函数,会立马返回。
4)ThreadSignal_Signal
void ThreadSignal_Signal(ThreadSignal *signal)
{
pthread_mutex_lock(&signal->mutex);
pthread_cond_signal(&signal->cond);
pthread_mutex_unlock(&signal->mutex);
}
后记 一个简单的信号等待操作,linux下处理起来就如此复杂,远不如c#、java等语言处理起来那么优雅。通过本文介绍的方法,将复杂的问题封装起来,让使用者用起来得心应手,这就是函数封装要达到的目的。
linux平台,对线程等待和唤醒操作的封装(pthread_cond_timedwait 用法详解)的更多相关文章
- WordPress 数据库操作WPDB对象($wpdb)用法详解【转载】
使用wordpress的时候,如果想直接使用WP里封装的数据库操作的类(wp-db.php),将wp-blog-header.php包含到代码中就可以使用了. define(‘PATH’, dirna ...
- PHP操作Excel – PHPExcel 基本用法详解
导出excel属性设置//Include classrequire_once('Classes/PHPExcel.php');require_once('Classes/PHPExcel/Writer ...
- java 多线程—— 线程等待与唤醒
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- java - 线程等待与唤醒
Java多线程系列--“基础篇”05之 线程等待与唤醒 概要 本章,会对线程等待/唤醒方法进行介绍.涉及到的内容包括:1. wait(), notify(), notifyAll()等方法介绍2. w ...
- Java 多线程基础(六)线程等待与唤醒
Java 多线程基础(六)线程等待与唤醒 遇到这样一个场景,当某线程里面的逻辑需要等待异步处理结果返回后才能继续执行.或者说想要把一个异步的操作封装成一个同步的过程.这里就用到了线程等待唤醒机制. 一 ...
- 转:一个跨WINDOWS LINUX平台的线程类
来源:http://blog.csdn.net/dengxu11/article/details/7232681 继Windows下实现一个CThread封装类之后,这里我再实现一个跨WINDOWS ...
- JUC在深入面试题——三种方式实现线程等待和唤醒(wait/notify,await/signal,LockSupport的park/unpark)
一.前言 在多线程的场景下,我们会经常使用加锁,来保证线程安全.如果锁用的不好,就会陷入死锁,我们以前可以使用Object的wait/notify来解决死锁问题.也可以使用Condition的awai ...
- kafka实战教程(python操作kafka),kafka配置文件详解
kafka实战教程(python操作kafka),kafka配置文件详解 应用往Kafka写数据的原因有很多:用户行为分析.日志存储.异步通信等.多样化的使用场景带来了多样化的需求:消息是否能丢失?是 ...
- linux curl用法详解
linux curl用法详解 curl的应用方式,一是可以直接通过命令行工具,另一种是利用libcurl库做上层的开发.本篇主要总结一下命令行工具的http相关的应用, 尤其是http下载方面 ...
随机推荐
- BeatifulSoup模块
一.介绍 Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你 ...
- 一.定时任务详解https://i.cnblogs.com/EditPosts.aspx
定时任务的详解 h每小时运行 d每天运行 w每周运行 m每个月运行 中毒时查看系统定时任务是否有病毒的脚本. crontab -l 查看用户的定时任务 crontab -e 进入编辑界面增加 ...
- 一个kubeadm.config文件--定义了token,扩展了默认端口,外部ETCD集群,自定义docker仓库,基于ipvs的kubeproxy
这个版本是基于kubeadm.k8s.io/v1alpha3的,如果到了beta1,可能还要变动呢. apiVersion: kubeadm.k8s.io/v1alpha3 kind: InitCon ...
- [转] 设置div的overflow:scroll,但是在手机上滑动的时候有点卡顿
设置div的overflow:scroll,但是在手机上滑动的时候有点卡顿,所以在这个div上加一个css: -webkit-overflow-scrolling : touch; 在苹果手机上使用- ...
- html5 之 local storage \sessjion storage
转载: HTMl5的sessionStorage和localStorage html5中的Web Storage包括了两种存储方式:sessionStorage和localStorage. sessi ...
- ynoi2018
题解: 全分块是啥操作啊.. 而且都好难.. 1.未来日记 这个比较简单 对每个块开个线段树维护权值 $n\sqrt{n}logn$ 这个会炸空间 并不能做... 但还是说一下做法 首先考虑分块 然后 ...
- 【BZOJ4998】星球联盟
题解: 应该还是比较水的 首先很容易发现的就是两个点一旦联通他们就永远联通了 所以联通之后我们就把他们之间缩成一个点
- 【译】你应该了解的JavaScript数组方法
让我们来做一个大胆的声明:for循环通常是无用的,而且还导致代码难以理解.当涉及迭代数组.查找元素.或对其排序或者你想到的任何东西,都可能有一个你可以使用的数组方法. 然而,尽管这些方法很有用,但是其 ...
- 【AtCoder】ARC073
ARC 073 C - Sentou 直接线段覆盖即可 #include <bits/stdc++.h> #define fi first #define se second #defin ...
- bootstrap AdminLTE模版的使用
参考: https://adminlte.io/themes/AdminLTE/documentation/index.html https://blog.csdn.net/gebitan505/ ...