如何正确设置sem_timedwait的timespec以防止EINVAL错误

时间:2014-08-12 00:20:52

标签: c semaphore time.h

我试图使用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值?

2 个答案:

答案 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;
}