2009-11-09 61 views

回答

8

如果你在Linux或類似的東西,可考慮使用named semaphores而不是(我假設是什麼)並行線程互斥。我不認爲有一種方法可以確定pthreads互斥量的鎖定PID,而不是構建自己的註冊表並將其放入共享內存。

+4

一般同意信號量建議,但POSIX信號量並不真正解決問題,因爲它們也不記錄鎖定過程的PID,也不會在不合時宜的死亡情況下解鎖。雖然它們可能是SysV信號量,但生鏽和笨拙的確會跟蹤PID,並且可以在使用SEM_UNDO選項調用時恢復。 – Duck 2009-11-09 22:07:20

1

您應該使用操作系統提供的信號量。

操作系統釋放進程已打開的所有資源,無論它是否死亡或正常退出。

+0

並非在所有資源。如果OP按照建議使用POSIX信號量,並且持有鎖的進程死亡,則信號量的值不會恢復,從而可能使其他進程死鎖。 – Duck 2009-11-09 19:37:13

1

只有當有人會有相同的想法並且會發現這個討論的使用時,我纔會退出這個錯誤的帖子!


您可以使用這種方法。 1)鎖定POSIX共享互斥鎖 2)將進程ID保存在共享內存中。 3)解鎖共享互斥 4)在正確的出口清潔過程-ID

如果進程核心轉儲下一過程會發現,在共享存儲器中有保存在步驟#2中的進程ID。如果在操作系統中沒有這個進程ID的進程,那麼沒有人擁有共享互斥。所以只需要替換進程ID。爲了回答評論

更新:

場景1:1。 開始P1 2. P1創建/打開一個名爲互斥體,如果它不存在 3. P1它timed_locks命名的互斥體和successfuly (如果需要,等待10秒); 4. P1 coredumps 5. P2在coredump後啓動 6. P2創建/打開一個已命名的互斥鎖,它存在,它是OK 7. P2 timed_locks已命名的互斥鎖並且無法鎖定(如果需要,等待10秒); 8. P2刪除命名的互斥體 9. P2再現了命名的互斥體&鎖定

+0

我在這裏沒有看到解決方案。情況1:(1)P1鎖; (2)P1死亡; (3)死鎖。情景2:(1)P1鎖; (2)P1寫pid; (3)P1解鎖; (4)P2得到控制並鎖定並找到P1 pid。場景3:如果切換順序以便在解鎖和進程死亡之前清除pid,則可以回到最初的問題,即死進程持有鎖並使其他進程死鎖。我錯過了什麼嗎? – Duck 2009-11-09 21:42:26

+0

評論場景#1 – 2009-11-10 16:13:31

+0

此更新無法使用。對任意時間的依賴是不好的。但更糟糕的是,如果超過1個進程試圖執行這個公式,那麼在刪除,重新創建,鎖定等互斥量的時候,所有地獄都可能崩潰。 – Duck 2009-11-10 21:12:37

5

基於文件的鎖定(使用flock(2))如何?當持有它的過程死亡時,它們會自動釋放。

演示程序:

#include <stdio.h> 
#include <time.h> 
#include <sys/file.h> 

void main() { 
    FILE * f = fopen("testfile", "w+"); 

    printf("pid=%u time=%u Getting lock\n", getpid(), time(NULL)); 
    flock(fileno(f), LOCK_EX); 
    printf("pid=%u time=%u Got lock\n", getpid(), time(NULL)); 

    sleep(5); 
    printf("pid=%u time=%u Crashing\n", getpid(), time(NULL)); 
    *(int *)NULL = 1; 
} 

輸出(我已經截斷了PID和次位爲清楚起見):

$ ./a.out & sleep 2 ; ./a.out 
[1] 15 
pid=15 time=137 Getting lock 
pid=15 time=137 Got lock 
pid=17 time=139 Getting lock 
pid=15 time=142 Crashing 
pid=17 time=142 Got lock 
pid=17 time=147 Crashing 
[1]+ Segmentation fault  ./a.out 
Segmentation fault 

什麼情況是,第一個節目獲得鎖,並開始睡5秒鐘。 2秒後,程序的第二個實例開始在試圖獲取鎖的同時阻塞。 3秒鐘後,第一個程序段錯誤(bash直到後來才告訴你),第二個程序獲得鎖定並繼續。

+0

我不認爲taht會被刪除,因爲無論是文件還是內存都是同樣的東西。 – Vivek 2009-11-14 08:05:06

+0

我的意思不是通過在文件中寫入某些東西(它確實是相似的),而是使用'flock(2)'。當你的進程死亡時,文件將被自動關閉,並且它的鎖定應該被釋放。 – Wim 2009-11-14 08:21:19

+0

+1只有flock(fileno(f),LOCK_EX | LOCK_NB)更安全 – dashesy 2012-05-03 17:04:40

30

似乎確切的答案已經以強健的互斥體的形式提供。

根據POSIX,可以使用pthread_mutexattr_setrobust()將pthread互斥鎖初始化爲「健壯」。如果持有該互斥鎖的進程死亡,下一個獲得它的線程將收到EOWNERDEAD(但仍然成功獲取互斥鎖),以便它知道執行任何清理。然後需要使用pthread_mutex_consistent()來通知獲取的互斥量再次一致。

很明顯,你需要內核和libc支持才能工作。在Linux上,內核支持被稱爲「健壯的futexes」,我發現引用了正在應用於glibc HEAD的用戶空間更新。

實際上,至少在Linux世界中,對此的支持似乎還沒有被濾除。如果這些函數不可用,您可能會發現pthread_mutexattr_setrobust_np(),就我所能收集而言,它似乎是一個提供相同語義的非POSIX前驅。我在Solaris文檔和Debian上的/usr/include/pthread.h中都找到了對pthread_mutexattr_setrobust_np()的引用。

POSIX規範可以在這裏找到:http://www.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_setrobust.html

+3

我認爲這是一個更好的答案。到目前爲止,我一直在Solaris上使用強大的互斥鎖。 – 2010-10-18 17:03:14

+2

強大的互斥體非常棒,但請注意,如果互斥體是在父進程中創建的,然後分叉和子進程同時持有互斥鎖,它們可能無法在glibc 2.15之前的GNU/Linux上正常工作。 [bug](http://sourceware.org/bugzilla/show_bug.cgi?id=13002)在glibc 2.15中修復。如果共享互斥體的兩個進程不是由分叉創建的父代和子代,那麼即使使用舊的glibc版本,健壯的互斥體也可以正常工作。 – 2013-01-10 23:27:52