tid - pthread\_cond\_timedwait på Windows returnerer ETIMEDOUT for tidligt

Indlæg af Hanne Mølgaard Plasc

Problem



Under pthreads-win32 2.7 og 2.8, vil pthread\_cond\_timedwait nogle gange vende tilbage med ETIMEDOUT. Der er kun en ventetråd og kun en signaltråd. Jeg tror ikke, at dette er tilfældet med betingelsesvariablen, ublockeret som i spørgsmålet: pthread\_cond\_timedwait vender tilbage straks


Internt kaldes Win32 pthread-implementeringen \_ftime () for at bestemme den aktuelle tid og sammenligner den med en absolut tid i fremtiden for at vente. Nøjagtigheden af ​​denne timer er utilstrækkelig (tror jeg), og den relative tid til at vente beregnes ofte forkert. Sig jeg beder om en ventetid på et sekund i fremtiden:


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 


Begge disse tilgange til bestemmelse af den aktuelle tid ikke blander godt med pthread-koden, der beregner antallet af millisekunder at vente givet en absolut tid, i ptw32\_relmillisecs.c (se slutningen af ​​dette indlæg) ptw32\_relmillisecs vil ofte returnere en lille antal millisekunder i stedet for de næsten 1000, der forventes.


Hvad jeg gør lige nu, går i gang med min egen timer, indtil timeout er virkelig gået, men jeg føler, at jeg skal beregne den fremtidige absolutte tid forkert.





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

Bedste reference