【sem_timedwait问题解决】系统时间向前跳变导致sem_timedwait长久阻塞
问题概述
系统时间跳变会导致一些系统时间依赖函数的异常工作,一个例子是sem_timedwait
。当处于sem_timedwait
阻塞等待时,如果此时系统时间跳变到起始时间之前:
1
sudo date -s "2025-06-30 9:40:00" //修改系统时间
那么sem_timedwait
会处于持续的阻塞状态,sem_timedwait
不会返回,也不会产生任何打印效果,如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using namespace std;
struct timespec ts{};
int main(){
sem_t sem_;
sem_init(&sem_,0,0);
while(true){
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += 20;
std::this_thread::sleep_for(std::chrono::seconds(10)); //在此延时内向前改变时间
if(sem_timedwait(&sem_, &ts)){ //没有获取到信号量
cout << "sem_timewait exit!" << endl;
break;
}else{ //获取到信号量
cout << "got semphore" <<endl;
break;
}
cout << "on Loop!" <<endl;
}
cout << "done" <<endl;
return 0;
}
问题解决:sem_trywait + 超时等待实现sem_timedwait
此处的解决方法是通过sem_trywait
去检测信号量,通过延时时间作超时等待,可以和sem_timedwait
等效:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23int mySemWait(sem_t* sem, int64_t waitTime_ms){
const int64_t MaxWaitTime = 10; //每次最大轮询时间为10ms
int64_t wait_pertime = 1; //单次等待时间,从1ms逐次递增
std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
int64_t duration = 0;
do{
if(sem_trywait(sem) == 0){
return 0;
}
if(errno != EAGAIN){
return -1;
}
int64_t leftTime = waitTime_ms - duration;
std::this_thread::sleep_for(std::chrono::milliseconds(std::min(leftTime, std::min(wait_pertime, MaxWaitTime))));
wait_pertime *= 2;
std::chrono::steady_clock::time_point endTime = std::chrono::steady_clock::now();
duration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count();
}while(duration < waitTime_ms);
return -1;
}
参考链接: