博客
关于我
C/C++ 修改系统时间,导致sem_timedwait 一直阻塞的问题解决和分析
阅读量:500 次
发布时间:2019-03-07

本文共 2852 字,大约阅读时间需要 9 分钟。

系统时间修改导致的sem_timedwait阻塞问题及解决方法

近期在项目修复中发现,系统时间向前修改后会导致sem_timedwait函数一直阻塞。经过深入分析和修复,最终找到了合适的解决方案。本文将详细阐述问题、原因及其解决方法。

问题描述

sem_timedwait函数的第二个参数是绝对时间戳,该函数会在绝对超时时间到达时才释放等待。假设当前系统时间为2019-08-05 18:13:20,传入的绝对等待时间为2019-08-05 18:15:00(100秒)。在sem_timedwait阻塞期间,如果系统时间被向前修改为2017-07-14 10:40:00,则sem_timedwait将因这个错误的时间判断而阻塞超过2年,严重影响系统正常运行。

sem_timedwait函数的缺陷

sem_timedwait的实现中,绝对时间戳是基于系统当前时间计算的。如果系统时间被修改,则会导致时间判断失真,从而引发意外的长期阻塞。

sem_timedwait的实现特点

语义:

  • 若信号量值为0,则立即返回errno=EAGAIN。

  • 若信号量值为负,则阻塞等待,直到超时或成功返回。

实现:

sem_timedwait的第二个参数是绝对超时时间戳,该参数会受到当前系统时间的影响。因此,如果在等待过程中,系统时间被修改,则sem_timedwait可能进入意外长时间的等待状态。

修复方案

通过sem_trywait加usleep的方式实现等待功能,避免因系统时间后修改导致的信息失真。

sem_trywait函数特点:

  • 非阻塞方式:sem_trywait函数执行时,不管信号量状态如何,都会立即返回。

sem_trywait和usleep结合的优势:

  • sem_trywait用于检测信号量是否为0,若为0则立即返回。

  • usleep用于实现可控制延时的阻塞等待。

实现方法

编写一个可靠的、以monotonic时钟为基准的等待函数,避免因系统时间调整而产生时间判断错误。

#include 
#include
#include
#include
#include
#include
#include
using namespace std;sem_t g_sem = SEMAPHORE_INITIALIZER;inline uint64_t GetTimeConvSeconds(timeval * curTime, uint32_t factor) { clock_gettime(CLOCK_MONOTONIC, curTime); return (uint64_t)(curTime->tv_sec) * factor;}uint64_t GetMonnotonicTime() { timeval curTime; uint64_t result = GetTimeConvSeconds(&curTime, 1000000); result += (uint32_t)(curTime.tv_nsec / 1000); return result;}bool Wait(size_t timeout) { size_t timeoutUs = timeout * 1000; size_t timeWait = 1; size_t delayUs = 0; uint64_t startUs = GetMonnotonicTime(); uint64_t elapsedUs = 0; do { if (sem_trywait(&g_sem) == 0) { return true; } if (errno != EAGAIN) { return false; } delayUs = timeoutUs - elapsedUs; if (delayUs <= 0) { timeWait = 1; } else { timeWait = min(delayUs, 10000); } if (usleep(timeWait) != 0) { return false; } elapsedUs = GetMonnotonicTime() - startUs; } while (elapsedUs <= timeoutUs); if (elapsedUs > timeoutUs) { return false; } return true;}bool SemTimedWait(size_t timeout) { timespec absTime; GetAbsTime(timeout, absTime); if (sem_timedwait(&g_sem, &absTime) != 0) { return false; } return true;}int main() { bool signaled = false; uint64_t startUs = GetMonnotonicTime(); uint64_t elapsedUs = 0; sem_init(&g_sem, 0, 0); // 通过sem_trywait + usleep 实现等待 signaled = Wait(1000); elapsedUs = GetMonnotonicTime() - startUs; cout << "signaled: " << signaled << "\tWait time: " << (elapsedUs / 1000) << "ms" << endl; // 使用sem_timedwait 示例(存在缺陷) startUs = GetMonnotonicTime(); signaled = SemTimedWait(2000); elapsedUs = GetMonnotonicTime() - startUs; cout << "signaled: " << signaled << "\tSemTimedWait time: " << (elapsedUs / 1000) << "ms" << endl; return 0;}

测试结果

运行程序可观察输出结果:

[root@lincoding sem]# ./sem_testsignaled: 0 Wait time:1000mssignaled: 0 SemTimedWait time:2000ms

总结

在编写信号量程序时,应尽量避免使用sem_timedwait函数来实现延时等待。若需要控制延时等待时间,建议采用sem_trywait + usleep的方式来避免因系统时间错误而引发的长时间阻塞问题。

转载地址:http://syzcz.baihongyu.com/

你可能感兴趣的文章
nnU-Net 终极指南
查看>>
No 'Access-Control-Allow-Origin' header is present on the requested resource.
查看>>
NO 157 去掉禅道访问地址中的zentao
查看>>
no available service ‘default‘ found, please make sure registry config corre seata
查看>>
no connection could be made because the target machine actively refused it.问题解决
查看>>
No Datastore Session bound to thread, and configuration does not allow creation of non-transactional
查看>>
No fallbackFactory instance of type class com.ruoyi---SpringCloud Alibaba_若依微服务框架改造---工作笔记005
查看>>
No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalanc
查看>>
No mapping found for HTTP request with URI [/...] in DispatcherServlet with name ...的解决方法
查看>>
No mapping found for HTTP request with URI [/logout.do] in DispatcherServlet with name 'springmvc'
查看>>
No module named 'crispy_forms'等使用pycharm开发
查看>>
No module named cv2
查看>>
No module named tensorboard.main在安装tensorboardX的时候遇到的问题
查看>>
No module named ‘MySQLdb‘错误解决No module named ‘MySQLdb‘错误解决
查看>>
No new migrations found. Your system is up-to-date.
查看>>
No qualifying bean of type XXX found for dependency XXX.
查看>>
No resource identifier found for attribute 'srcCompat' in package的解决办法
查看>>
no session found for current thread
查看>>
No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-android
查看>>
NO.23 ZenTaoPHP目录结构
查看>>