我试图使用sem_timedwait()重复锁定和解锁信号量。基于示例here,我以下列方式设置我的struct timespec,持续20毫秒的超时:
sem_t semaphore; //initialized somewhere else
void waitForSomething ()
{
int ret;
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
{
//throw error
}
ts.tv_nsec += 20000000; //timeout of 20 msec
while ((ret = sem_timedwait(&semaphore, &ts)) == -1 && errno == EINTR)
continue;
if (ret == -1 && errno != ETIMEDOUT) {
//flag error
} else {
//do something
}
return;
}
使用上面的代码,我的程序在使用EINVAL错误代码运行一段时间后会一直失败。经过调试后,我意识到失败的原因是ts.tv_nsec在一段时间后超过了1000000000。我目前的解决方法如下:
sem_t semaphore; //initialized somewhere else
void waitForSomething ()
{
int ret;
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
{
//throw error
}
if (ts.tv_nsec > 979999999) {
ts.tv_sec += 60;
ts.tv_nsec = (ts.tv_nsec + 20000000) % 1000000000;
} else {
ts.tv_nsec += 20000000;
}
while ((ret = sem_timedwait(&semaphore, &ts)) == -1 && errno == EINTR)
continue;
if (ret == -1 && errno != ETIMEDOUT) {
//throw error
} else {
// do something
}
return;
}
我想知道 - 有没有更好的方法来做到这一点,而无需自己直接调整timespec值?
答案 0 :(得分:5)
据我所知,您需要在timespec
添加间隔后正确 规范化 tv_nsec
结构。
你可以做的一件事是:
ts.tv_nsec += 20000000;
ts.tv_sec += ts.tv_nsec / 1000000000;
ts.tv_nsec %= 1000000000;
在Linux内核中,您可以使用set_normalized_timespec()
为您执行规范化。请参阅here。
答案 1 :(得分:1)
看起来您的解决方法是错误的:您希望等待20毫秒,但在纳秒计数太大的情况下,您需要添加60秒:ts.tv_sec += 60;
你的解决方法应该是这样的:
ts.tv_nsec+=20000000;
if (ts.tv_nsec>=1000000000) {
ts.tv_sec+=1;
ts.tv_nsec-=1000000000;
}