2011-12-17 75 views
3

操作系統:Linuxpthread_mutex_timedlock不超時

LIB:glibc的

我有訪問一塊硬件,我通過使用一個互斥防止爭用的多個線程。

該軟件非常複雜,並且由於遞歸調用鎖,可能會導致系統死鎖。出於這個原因,我正在使用'pthread_mutex_timedlock'而不是'pthread_mutex_lock'。我寧願打印一條錯誤消息,然後繼續導致系統看門狗和復位。這可以讓我看到這個問題,而不會使系統失效。

這裏有一段代碼應該可以幫助你理解我正在嘗試做什麼。

pthread_mutex_t MainMutex = PTHREAD_MUTEX_INITIALIZER; 

#define m_TAKE_LOCK() { \ 
          struct timespec abs_time; \ 
          clock_gettime(CLOCK_REALTIME , &abs_time); \ 
          abs_time.tv_sec += 5; \ 
          if (pthread_mutex_timedlock (&MainMutex, &abs_time) != 0) \ 
          { \ 
           printf("Lock failed PID %d %s\n", getpid(), __func__); \ 
          } \ 
         } 

#define m_RELEASE_LOCK() pthread_mutex_unlock(&MainMutex); 

void func1(void) {m_TAKE_LOCK()} 
void func2(void) {m_TAKE_LOCK()} 

void main(void) 
{ 
    while (1) 
    { 
    func1(); 
    func2(); 
    m_RELEASE_LOCK() 
    ... 
    } 
} 

還有其他線程也採取鎖,但這不是一個問題。我遇到的問題是永遠不會出現鎖定超時。它永遠在等待,並監督這個系統,這正是我想要避免的。

'abs_time.tv_sec'是正確的 - 我已經打印了它,系統時鐘已經被我嘗試和使用它的時間初始化了。

我知道Windows將阻止同一進程的鎖定,但Linux沒有這種保護。我意識到我不應該遞歸調用m_TAKE_LOCK(),但使用timedlock的目的是捕捉錯誤(打印消息並繼續)。

任何人都知道我可能做錯了什麼?

+1

如果您使用`pthread_mutexattr_settype(3posix)`將互斥鎖設置爲鍵入`PTHREAD_MUTEX_RECURSIVE`,您應該能夠在單個線程中遞歸獲取您的鎖。 – sarnold 2011-12-17 01:09:06

+2

樣式問題:您應該使用`do {...} while(0)`而不是`{...}`,因爲它允許將`;`附加到它的調用 - 這更好。並將它用於TAKE和RELEASE。 – fge 2011-12-17 01:10:31

回答

4

您無法嘗試獲取您已擁有的互斥鎖。這是不允許的。你假設它會產生一個特定的結果,並不能保證它會這樣做。

您應該使用遞歸互斥鎖。你應該釋放它相同的次數,你獲得它。然而,從根本上講,這是一個絕對的要求,即任何獲取互斥鎖的代碼都知道它在運行時擁有哪些互斥鎖,這些互斥鎖與該函數可能直接或間接調用的代碼有關。 (它不需要知道由調用它的代碼持有的'高級'互斥體,但它可以被調用的功能未觸及。)

例如,如果您正在創建一個名爲「Foo」的類,調用「Bar」時,「Foo」類的每個函數都必須知道它與「Foo」或「Bar」關聯的鎖。如果某個新類「Qux」調用它,則「Foo」代碼不需要知道「Qux」鎖是什麼,但如果「Qux」在鎖定「Bar」時調用「Foo」,則「Foo」功能必須知道這一點。您必須實現一個合理的鎖定層次結構。 (除非你完全理解這條規則的基本原理,並且確定它不適用。)否則,除非偶爾運氣,否則你的代碼將永遠不會正常工作。

POSIX spec不需要超時:「如果不等待另一個線程解鎖互斥鎖,互斥鎖就不能鎖定,那麼當指定的超時到期時,該等待將被終止。沒有其他線程可以等待。它也不需要錯誤,「如果發生以下情況,pthread_mutex_timedlock()函數可能會失敗: [EDEADLK]檢測到死鎖條件或當前線程已擁有該互斥鎖。」 「可能」表示支持是可選的錯誤條件,術語「將失敗」用於表示所需的行爲。

+0

感謝您花時間回答這個問題。你對posix規格的引用很清楚,但我忽略了它。我將調查一個遞歸鎖。看起來,它更適合我的需要,以防止在對互斥鎖進行非預期的遞歸調用期間系統掛起。 – ObnoxiousKiwi 2011-12-17 04:45:00

1

你的代碼工作以及我的Linux機器上:

[email protected]:~$ gcc test.c -o test -lpthread -lrt 
[email protected]:~$ ./test 
Lock failed PID 2333 func2 
Lock failed PID 2333 func2 
Lock failed PID 2333 func2 
Lock failed PID 2333 func2 
^C 

這是我所期望的輸出。