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

Linux使用信号量sem_timedwait当作定时器

主要是通过判断信号量等待超时,然后达到计时的目的。

头文件:

#include<semaphore.h>

信号量初始化

sem_init(&p_sem, 0, 0);

获取当前系统时间

structtimespects;

clock_gettime(CLOCK_REALTIME, &ts);

此函数用来获得当前时间,结果存入structtimespec。CLOCK_REALTIME指从1970.1.1到目前的时间。

/* Get current value of clock CLOCK_ID and store it in TP. */ extern int clock_gettime (clockid_t __clock_id, struct timespec *__tp) __THROW; /* Identifier for system-wide realtime clock. */ # define CLOCK_REALTIME 0 struct timespec结构体存储的是时间戳,某一刻的时间,一个成员表示秒,一个成员表示纳秒。 /* POSIX.1b structure for a time value. This is like a `struct timeval' but has nanoseconds instead of microseconds. */ struct timespec { __time_t tv_sec; /* Seconds. */ __syscall_slong_t tv_nsec; /* Nanoseconds. */ };

//等待信号量,超时时间为下一次调用的时间点

sem_timedwait(p_sem, &ts);

如果p_sem 信号量值>0,则sem_timedwait 立即返回;如果sem 信号量值≤0,则 sem_timedwait 阻塞等待 TIMEOUT秒后再返回。

第二个参数表示TIMEOUT时间,注意这个地方,它指定一个时间点而不是时间段,这个时间点用结构体表示,结构体以自1970-01-01 00:00:00起,到目前为止的时间。

这个时间点要晚于调用时的时间点,可以理解成阻塞到未来某个时间点。

这个超时的时间就相当于定时了。跟sleep一段时间类似。而且与C++的std::this_thread::sleep_for 里面的sleep相比,效果差不多。

写个例子验证一下:

#include <stdio.h> #include <fcntl.h> #include <sys/stat.h> #include <semaphore.h> #include <time.h> #include <errno.h> #include <iostream> #include <chrono> #include <thread> using namespace std; int main(int argc, const char *argv[]) { sem_t p_sem; int ret = 0; int value = 0; /* 创建信号量 */ //p_sem = sem_open("mysem2", O_CREAT, 0666, 1); /* 信号量初值为1 */ sem_init(&p_sem, 0, 0); const int count=200; u_int64_t count1 = 0, count2 = 0; for (int i=0; i<count; ++i) { struct timespec ts, ts_end; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_nsec += 100000000; //100ms if (ts.tv_nsec >= 1000000000) { ts.tv_nsec -= 1000000000; ts.tv_sec += 1; } // 等待信号量,超时时间为下一次调用的时间点 sem_timedwait(&p_sem, &ts); //超时时间100ms clock_gettime(CLOCK_REALTIME, &ts_end); count1 += (ts_end.tv_nsec - (ts.tv_nsec - 100000000) + (ts_end.tv_sec - ts.tv_sec) * 1000000000); } for (int j=0; j<count; j++) { auto begin = std::chrono::system_clock::now(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); auto end = std::chrono::system_clock::now(); auto result = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count(); count2 += result; } //对比sem_timedwait和sleep_for的精确度,运行相同次数和相同的定时后取平均值,值越接近100000000越精确 std::cout<<"sem_timedwait 平均时间: "<<(count1/count)<<" \nsleep_for平均时间: \t"<<(count2/count)<<std::endl; sem_destroy(&p_sem); getchar(); return 0; }

#g++ -o sem sem.cpp -lpthread

程序先用clock_gettime(CLOCK_REALTIME, &ts); 获取当前时间,然后通过

ts.tv_nsec += 100000000;

延时100ms。这里的 tv_nsec有可能溢出,所以要判断处理一下。

if (ts.tv_nsec >= 1000000000)

{

ts.tv_nsec -= 1000000000;

ts.tv_sec += 1;

}

然后调用sem_timedwait(p_sem, &ts);等待超时。超时后调用

clock_gettime(CLOCK_REALTIME, &ts_end);

获取调用后的时间,与开始的时间做个差值得到程序运行时间。为了更准确,循环200此取平均值。

为了对比效果,下面使用std::this_thread::sleep_for()进行了对比,同样休眠100ms,运行200次取平均值,并实验多次。

第一次结果:

第二次结果:

第三次结果:

第四次结果:

第五次结果:

第六次结果:

可以看出sem_timedwait()和 std::this_thread::sleep_for的效果差不多。

如果二者都支持的环境下,使用std::this_thread::sleep_for更方便一些。

如果是C语言环境,可以使用sem_timedwait,封装一下,具有定时功能,同样能保证精度。

封装定时函数

#include <stdio.h> #include <fcntl.h> #include <sys/stat.h> #include <semaphore.h> #include <time.h> #include <errno.h> #include <iostream> #include <chrono> #include <thread> using namespace std; //纳秒 void Sleep_Sem_ns(uint64_t nanoseconds) { const uint64_t ONE_SECOND_MS = 1000000000; sem_t p_sem; sem_init(&p_sem, 0, 0); struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += nanoseconds / ONE_SECOND_MS; ts.tv_nsec += nanoseconds % ONE_SECOND_MS; if (ts.tv_nsec >= ONE_SECOND_MS) { ts.tv_nsec -= ONE_SECOND_MS; ts.tv_sec += 1; } sem_timedwait(&p_sem, &ts); //超时时间100ms sem_destroy(&p_sem); } //毫秒 void Sleep_Sem_ms(uint64_t milliseconds) { Sleep_Sem_ns(milliseconds * 1000 * 1000); } //秒 void Sleep_Sem_s(uint64_t seconds) { Sleep_Sem_ns(seconds * 1000 * 1000 * 1000); }

测试一下是否好用

int main(int argc, const char *argv[]) { auto begin = std::chrono::system_clock::now(); Sleep_Sem_ns(100000000); auto end = std::chrono::system_clock::now(); std::cout<< std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count() <<std::endl; begin = std::chrono::system_clock::now(); Sleep_Sem_ms(200); end = std::chrono::system_clock::now(); std::cout<< std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() <<std::endl; begin = std::chrono::system_clock::now(); Sleep_Sem_s(2); end = std::chrono::system_clock::now(); std::cout<< std::chrono::duration_cast<std::chrono::seconds>(end - begin).count() <<std::endl; return 0; }

测试结果:

http://www.jsqmd.com/news/502473/

相关文章:

  • 编程语言扩展与驱动交互 - C扩展
  • 【JUC 一】线程 进程 synchronized Lock锁 生产者 消费者 8锁 线程安全集合类...
  • 企业上云如何避坑?2026年主流云主机深度对比与决策指南 - 资讯焦点
  • 深入解析PE内存注入技术:从文件到shellcode的转换机制
  • Python爬虫进阶:自动化采集语音训练数据实战
  • 国内云平台选购指南:主流服务对比与价格解析 - 资讯焦点
  • macOS鼠标滚动优化解决方案:提升效率的平滑滚动技术实现
  • MATLAB R2023b安装包下载及安装步骤说明
  • Phi-3-Mini-128K实战:利用卷积神经网络原理优化模型提示策略
  • 2026南京定制假发优质公司推荐榜 - 资讯焦点
  • 郑州叮叮智能荣登2026行业十大品牌,新晋实力派彰显领军风范 - 深度智识库
  • 2026年青岛留学中介哪家口碑好:五家优选深度解析 - 科技焦点
  • webpack的使用步骤及插件使用方法
  • 武汉医美哪家好?推荐几家靠谱的武汉医疗美容和机构 - 资讯焦点
  • HPatches数据集实战:从特征点检测到匹配精度的全链路评估
  • ROS+Prescan+Carsim联调实战:手把手搭建自动驾驶硬件在环测试平台(附避坑指南)
  • 选对名师少走弯路,药学主任药师考试高分名师推荐 - 医考机构品牌测评专家
  • EasyAnimateV5-7b-zh-InP与Typora结合:Markdown文档转视频教程
  • 别再跟风“代装”了!2026年OpenClaw“养虾”避坑实战指南
  • 2026年青岛留学机构推荐:五家优选深度解析 - 科技焦点
  • SeqGPT-560m轻量生成教程:从零训练专属领域微调版本完整流程
  • 存算一体C封装性能断崖式下降的真相:Cache Line对齐缺失、MMIO屏障遗漏、DMA描述符链错序(附GDB+Trace32联合调试清单)
  • 4.2.2 存储->POSIX 文件系统标准(IEEE,ISO IEC 采纳):Btrfs(B-tree File System)B 树文件系统
  • Gemma-3-12b-it图文问答效果展示:古籍扫描件识别+繁体转简体+释义
  • 深求·墨鉴(DeepSeek-OCR-2)效果展示:水墨留痕可视化识别过程
  • AI 生产与全民 Claw 时代:低门槛工具如何改变生产力格局
  • 能提升客户服务的 CRM 系统推荐 - SaaS软件-点评
  • SiamMask核心原理深度解析:孪生网络如何统一跟踪与分割
  • Emotion2Vec+快速入门:无需代码,用WebUI轻松识别语音情感
  • 高级职称外科护理讲师硬核测评|苏菲老师专属适配性全解析 - 医考机构品牌测评专家