在pthreads-win32 2.7和2.8下,pthread_cond_timedwait有时会在ETIMEDOUT时过早返回。只有一个等待线程和一个信令线程。我不相信这是条件变量虚假解除阻塞的情况,如问题:pthread_cond_timedwait returning immediately
Win32 pthread实现在内部调用_ftime()来确定当前时间,并将其与将来等待的绝对时间进行比较。这个计时器的准确性是不够的(我认为),因此等待的相对时间通常不正确。假设我要求等待一秒钟:
struct timespec ts;
ts.tv_sec = static_cast<long>(time(NULL) + sec_rel);
ts.tv_nsec = 0;
// OR
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代码不能很好地混合,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;
}