В pthreads-win32 2.7 и 2.8 pthread_cond_timedwait иногда возвращается слишком рано с ETIMEDOUT.Существует только один ожидающий поток и только один сигнальный поток.Я не верю, что это случай случайной разблокировки условной переменной, как в вопросе: pthread_cond_timedwait, возвращающийся немедленно
Внутренне реализация Win32 pthread вызывает _ftime (), чтобы определить текущее время, исравнивает это с абсолютным временем ожидания в будущем.Точность этого таймера недостаточна (я думаю), поэтому относительное время ожидания часто вычисляется неправильно.Скажем, я прошу подождать секунду в будущем:
struct timespec ts;
ts.tv_sec = static_cast<long>(time(NULL) + sec_rel);
ts.tv_nsec = 0;
// ИЛИ
struct timespec ts;
struct _timeb currSysTime;
_ftime(&currSysTime);
ts.tv_sec = static_cast<long>(currSysTime.time + sec_rel);
ts.tv_nsec = currSysTime.millitm * 1000000;
if( pthread_cond_timedwait(&m_cond, &m_Mutex, &ts) ) // returns too early
Оба эти подхода для определения текущего времени плохо сочетаются с pthreadкод, который вычисляет количество миллисекунд ожидания для данного абсолютного времени, в ptw32_relmillisecs.c (см. конец этого поста) ptw32_relmillisecs будет часто возвращать небольшое количество миллисекунд, а не ожидаемую почти 1000.
То, что я сейчас делаю, - это цикл с моим собственным таймером до истечения времени ожидания, но я чувствую, что, должно быть, неправильно вычисляю будущее абсолютное время.
INLINE DWORD
ptw32_relmillisecs (const struct timespec * abstime)
{
const int64_t NANOSEC_PER_MILLISEC = 1000000;
const int64_t MILLISEC_PER_SEC = 1000;
DWORD milliseconds;
int64_t tmpAbsMilliseconds;
int64_t tmpCurrMilliseconds;
struct _timeb currSysTime;
/*
* Calculate timeout as milliseconds from current system time.
*/
/*
* subtract current system time from abstime in a way that checks
* that abstime is never in the past, or is never equivalent to the
* defined INFINITE value (0xFFFFFFFF).
*
* Assume all integers are unsigned, i.e. cannot test if less than 0.
*/
tmpAbsMilliseconds = (int64_t)abstime->tv_sec * MILLISEC_PER_SEC;
tmpAbsMilliseconds += ((int64_t)abstime->tv_nsec + (NANOSEC_PER_MILLISEC/2)) / NANOSEC_PER_MILLISEC;
/* get current system time */
_ftime(&currSysTime);
tmpCurrMilliseconds = (int64_t) currSysTime.time * MILLISEC_PER_SEC;
tmpCurrMilliseconds += (int64_t) currSysTime.millitm;
if (tmpAbsMilliseconds > tmpCurrMilliseconds)
{
milliseconds = (DWORD) (tmpAbsMilliseconds - tmpCurrMilliseconds);
if (milliseconds == INFINITE)
{
/* Timeouts must be finite */
milliseconds--;
}
}
else
{
/* The abstime given is in the past */
milliseconds = 0;
}
return milliseconds;
}