2011-09-23 34 views
1

我正在開發用戶級線程庫作爲項目的一部分。我想出了一個實現互斥鎖的方法。在繼續之前,我希望看到你的意見。基本上,我需要實現僅有3職能在我的圖書館在用戶級線程庫中實現互斥體

調用mutex_init,的mutex_lock和mutex_unlock

我想我爲mutex_t結構看起來像

typedef struct 
{ 
    int available; //indicates whether the mutex is locked or unlocked 
    queue listofwaitingthreads; 
    gtthread_t owningthread; 
}mutex_t; 

在我的mutex_lock功能,我會首先檢查如果互斥量在while循環中可用。如果不是的話,我會讓下一個線程執行的處理器。

在我mutex_unlock功能,我將檢查所有者線程是當前線程。如果是,我就可以設置爲0。

這是去了解它的方式嗎?另外,死鎖呢?我是否應該照顧用戶級庫中的這些條件,還是應該讓應用程序員正確編寫代碼?

+0

如果沒有其他線程準備好運行,那麼yielding是一個no操作,所以你會有一個繁忙的循環。您是否正在尋找一個沒有互斥鎖的平臺? –

+0

難道你不需要另一個互斥鎖來鎖定正在被操作的等待線程列表嗎? – Dipstick

回答

8

這不起作用,因爲你有競爭條件。如果2個線程同時嘗試鎖定,則兩個線程都會看到available == 0,並且兩個線程都認爲他們成功執行了互斥鎖。

如果你想這樣做正確,並且不使用已經存在的鎖,你必須訪問諸如TAS,CAS硬件操作等

有算法,讓你沒有這樣的硬件支持互斥,但是他們做出了許多假的假設。有關更多細節,我強烈建議您閱讀赫利希和沙維特的多處理器編程的藝術,第7章

你不應該擔心死鎖在這個水平 - 互斥鎖應該足夠簡單,且有一定的假定使用它們的程序員應該注意不要導致死鎖(高級互斥鎖可以檢查自我死鎖,意味着一個線程可以在不調用中間位置的情況下調用兩次鎖)。

+0

「,兩人都會認爲他們成功地接受了互斥體。」他們不能簡單地檢查自己的線程,看看他們是否真的獲得了鎖定? – LVB

+0

@LVB按照什麼順序建議設置擁有線程,設置可用並檢查owningreadread? –

+0

沒關係...我開始回憶起更多關於這些問題的內容,並且現在看到它爲什麼不起作用。 – LVB

0

不僅如此,你所要做的原子操作來讀取和修改的標誌(如伊蘭指出的),你還必須看你的隊列能夠有併發訪問。這並非完全微不足道的,有點像母雞和雞蛋的問題。

但是,如果你真的實現這個由紡紗,你甚至不會需要有這樣的隊列。不過,鎖的訪問順序主要是隨機的。

可能只是產生也將是不夠的,這可以,如果你有持有鎖超過一些處理器週期線程是相當昂貴的。考慮使用nanosleep等待時間較短的值。

0

一般來說,mutex的實現應該是這樣的:

鎖:

while (trylock()==failed) { 
    atomic_inc(waiter_cnt); 
    atomic_sleep_if_locked(); 
    atomic_dec(waiter_cnt); 
} 

的tryLock:

return atomic_swap(&lock, 1); 

解鎖:

atomic_store(&lock, 0); 
if (waiter_cnt) wakeup_sleepers(); 

事情得到,如果更復雜你想要復發可以同步其自身破壞的互斥體,互斥體(即互斥體)。釋放互斥只要你獲得鎖)是安全的,等

注意atomic_sleep_if_lockedwakeup_sleepers對應於Linux上FUTEX_WAITFUTEX_WAKE歡聲笑語。其他原子可能是CPU指令,但可能是系統調用或內核輔助的用戶空間函數代碼,例如Linux/ARM和0xffff0fc0原子比較和交換調用。

0

因爲所有線程都將是同一進程的用戶級線程,所以您不需要用戶級線程庫的原子指令。所以實際上,當你的進程被賦予時間片執行時,你在那個時間片內運行多個線程,但在同一個處理器上運行。所以,沒有兩個線程將同時在庫函數中。考慮到互斥體的功能已經存在於庫中,互斥被保證。