2012-08-02 77 views
0
早期

下面的程序產生以下輸出:那麼pthread_cond_timedwait返回1秒

$ ./test_condvar 9000 
1343868189.623067126 1343868198.623067126 FIRST 
1343868197.623132345 1343868206.623132345 TIMEOUT 
1343868205.623190120 1343868214.623190120 TIMEOUT 
1343868213.623248184 1343868222.623248184 TIMEOUT 
1343868221.623311549 1343868230.623311549 TIMEOUT 
1343868229.623369718 1343868238.623369718 TIMEOUT 
1343868237.623428856 1343868246.623428856 TIMEOUT 

注意,跨行讀取顯示的預期9秒鐘時間增量,但向下讀取列顯示pthread_cond_timedwait返回在8秒ETIMEDOUT。

並行線程的lib是的glibc 2.12。運行Red Hat EL6。 uname -a顯示2.6.32-131.12.1.el6.x86_64 #1 SMP Tue Aug 23 11:13:45 CDT 2011 x86_64 x86_64 x86_64 GNU/Linux

它看起來像pthread_cond_timedwait依賴於lll_futex_timed_wait超時行爲。

在別的地方尋找一個解釋任何想法?

#include <time.h> 
#include <sys/time.h> 
#include <pthread.h> 
#include <errno.h> 
#include <stdlib.h> 
#include <stdio.h> 

int main (int argc, char *argv[]) 
{ 
    pthread_mutexattr_t mtx_attr; 
    pthread_mutex_t mtx; 
    pthread_condattr_t cond_attr; 
    pthread_cond_t cond; 

    int milliseconds; 
    const char *res = "FIRST"; 

    if (argc < 2) 
    { 
     fputs ("must specify interval in milliseconds", stderr); 
     exit (EXIT_FAILURE); 
    } 

    milliseconds = atoi (argv[1]); 

    pthread_mutexattr_init (&mtx_attr); 
    pthread_mutexattr_settype (&mtx_attr, PTHREAD_MUTEX_NORMAL); 
    pthread_mutexattr_setpshared (&mtx_attr, PTHREAD_PROCESS_PRIVATE); 

    pthread_mutex_init (&mtx, &mtx_attr); 
    pthread_mutexattr_destroy (&mtx_attr); 

#ifdef USE_CONDATTR 
    pthread_condattr_init (&cond_attr); 
    if (pthread_condattr_setclock (&cond_attr, CLOCK_REALTIME) != 0) 
    { 
     fputs ("pthread_condattr_setclock failed", stderr); 
     exit (EXIT_FAILURE); 
    } 

    pthread_cond_init (&cond, &cond_attr); 
    pthread_condattr_destroy (&cond_attr); 
#else 
    pthread_cond_init (&cond, NULL); 
#endif 

    for (;;) 
    { 
     struct timespec now, ts; 
      clock_gettime (CLOCK_REALTIME, &now); 

     ts.tv_sec = now.tv_sec + milliseconds/1000; 
      ts.tv_nsec = now.tv_nsec + (milliseconds % 1000) * 1000000; 
     if (ts.tv_nsec > 1000000000) 
     { 
      ts.tv_nsec -= 1000000000; 
      ++ts.tv_sec; 
     } 

     printf ("%ld.%09ld %ld.%09ld %s\n", now.tv_sec, now.tv_nsec, 
       ts.tv_sec, ts.tv_nsec, res); 

     pthread_mutex_lock (&mtx); 
     if (pthread_cond_timedwait (&cond, &mtx, &ts) == ETIMEDOUT) 
      res = "TIMEOUT"; 
     else 
      res = "OTHER"; 
     pthread_mutex_unlock (&mtx); 
    } 
} 

回答

7

有一個飛躍的插入第二,今年7月1日,這導致futexes的太早到期的1秒鐘,直至任一機器重新啓動或運行了解決辦法引發了Linux kernel bug

# date -s "`date`" 

這聽起來像你已經通過咬傷。

+0

就是這樣!謝謝。 – 2012-08-16 18:45:08

+0

+1,因爲這顯然是這個問題上最容易找到的答案 - 這讓我們幾個人在這裏困難了幾天...... – bythescruff 2012-08-20 08:28:46

0

我不知道,這是涉及到具體問題,但你行:

if (ts.tv_nsec > 1000000000) 

真的應該是:

if (ts.tv_nsec >= 1000000000) 

而且,事實上,如果你這樣做意想不到的事情和傳中10000(例如),你可能要考慮將它:

while (ts.tv_nsec >= 1000000000) 

儘管它可能在某些時候最好使用模算術,這樣循環沒有運行的時間過長。

除此之外,這似乎是某種問題與您的環境。該代碼工作正常,我的Debian,Linux MYBOX 2.6.32-5-686 #1 SMP Sun May 6 04:01:19 UTC 2012 i686 GNU/Linux下:

1343871427.442705862 1343871436.442705862 FIRST 
1343871436.442773672 1343871445.442773672 TIMEOUT 
1343871445.442832158 1343871454.442832158 TIMEOUT 
: 

一個可能性的是,系統時鐘不是神聖不可侵犯的 - 它可以定期NTP或其他時間的同步過程進行修改。我提到這是一種可能性,但似乎有點奇怪,它會在暫停和獲得當前時間之間的短時間內發生。

一個測試是使用不同的超時時間(例如交替七秒和十三秒)來查看效果是否相同(這些數字被選爲質數並且不太可能是其他任何活動的倍數。系統

+0

在不同的內核上試用它表明它工作正常。使用交替間隔表現出相同的行爲。奇怪,但使用不同內核的解決方法已經足夠了。 – 2012-08-02 13:14:14

+0

@Joe,我仍然提出一個針對RHEL的錯誤。所有那些你毫無疑問付費的許可費至少應該給你這個權利。 – paxdiablo 2012-08-02 14:00:41