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

sha*_*ols 1 c semaphore time.h

我正在尝试使用sem_timedwait()来重复锁定和解锁信号量.根据这里的示例,我按以下方式设置我的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;
}
Run Code Online (Sandbox Code Playgroud)

使用上面的代码,我的程序在使用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;
}
Run Code Online (Sandbox Code Playgroud)

我想知道 - 有没有更好的方法来做到这一点,而无需自己直接调整timespec值?

Eri*_*c Z 7

据我所知,你需要正常化一个timespec结构添加的间隔后正常tv_nsec.

你能做的一件事是:

ts.tv_nsec += 20000000;
ts.tv_sec += ts.tv_nsec / 1000000000;
ts.tv_nsec %= 1000000000;
Run Code Online (Sandbox Code Playgroud)

在Linux内核中,您可以使用set_normalized_timespec()为您执行规范化.请参阅此处.