pthread_cond_timedwait в Windows возвращает ETIMEDOUT слишком рано - PullRequest
0 голосов
/ 19 марта 2012

В 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...