2011-10-12 151 views
2

所以我知道你可以使用一個信號量和其他可能的方法來確定一個鎖是否會成功和/或有多少個線程在等待鎖,但是你可以在鎖定自己?如何測試鎖內等待線程

我的情況是我有一個事件處理程序,可以由List中的許多對象調用。我想在一個鎖內做一個測試,看看在繼續之前所有的對象是否處於正確的狀態。對象過渡到適當的狀態然後引發此事件,因此在單個線程模型中,當最後一個引發此事件時,所有對象都處於正確狀態,我們繼續。但是在我看來,使用多線程時,多個對象可能會轉換到我正在檢查的狀態,但尚未處理此事件,因爲它們正在等待鎖定。因此,鎖內的條件狀態檢查將是真實的,但是直到所有線程完成處理該事件爲止都將繼續執行。我只需要它是真實的,因爲最後一個線程被處理,以確保我們不會太快。

例如,在半寫實代碼:

object _LockObj = new object(); 

void Event_Handler(object sender, EventArgs e) 
{ 
    MyObject originator = sender as MyObject; 
    if(originator == null) 
     return; 

    *Do stuff with the originator* 

    lock(_LockObj) 
    { 
     if(ListOfMyObjects.FindAll(o => o.State == DesiredState) 
          .Count == ListOfMyObjects.Count 
           && *nothing waiting at the lock*) 
     { 
      *Proceed* 
     } 
    } 
} 

我完全願意接受我的做法是臭下手,並且我正在尋找解決的辦法是沒有實際意義,如果我在做正確首先,但我不確定如何以線程安全的方式正確執行此操作。

我打算給MyObject添加更多狀態,並通過在*Do stuff with the originator*部分設置相應的狀態來管理流程,但是從這裏轉換MyObject並不合適,更不用說我必須實現一個爲每個引發異味變得不簡單的事件狀態持有狀態!

因此,如果有做「沒有設定鎖定等待」檢查那麼這就是我想去除非我失去了一個非常簡單的實現模式,有助於在這種情況下的方式的簡單方法。

+1

您正在尋求一個線程比賽錯誤作爲功能。在你斷定沒有線程正在等待之後的一個納秒內,一個線程可以進入該方法。 –

回答

3

首先,不幸的是,測試其他等待lock()語句的線程不會得到你想要的結果。例如,如果對象A,B和C已經轉換到所需的狀態並且已經提升了事件,那麼可能僅對一個對象調用Event_Handler,在那一點上稱爲A。稍後,相同的處理程序將在某個時刻爲B和C運行。所以你所有的對象現在應該處於期望的狀態,並且沒有線程在鎖上等待,但是你有可能。不想「繼續」。即使你這樣做,你也需要考慮,同樣的事情可能會在B之後立即發生,然後再爲C發生,所以「繼續」可能會運行三次...

這是一個簡單的建議,但您可以使用反擊測試有多少對象實際上引發了事件。如果櫃檯沒有提供足夠的信息,您也可以使用其他清單。重要的一點是,無論您使用哪種方法,只需在同一個_LockObj的鎖內更新計數器/列表/其他機制。然後可能在繼續運行後重置該計數器。如果您需要訪問其他地方的計數器,請確保您使用相同的lock(_LockObj),這將確保您在其他關鍵部分內不會更改計數器。

object _LockObj = new object(); 
int _counter = 0; 

void Event_Handler(object sender, EventArgs e) 
{ 
    MyObject originator = sender as MyObject; 
    if(originator == null) 
     return; 

    *Do stuff with the originator* 

    lock(_LockObj) 
    { 
     ++_counter; 
     if (_counter == ListOfMyObjects.Count) 
     { 
      *Proceed* 

      _counter = 0; 
     } 
    } 
} 

編輯:去除對象的狀態冗餘校驗。

+0

這次複查沒用嗎?如果這兩個部分不符合,你將永遠無法進入。 – xanatos

+0

謝謝@xanatos,已經更新了代碼。代碼的其他部分可能會更新對象的狀態,我們仍然需要檢查它,但是如果是這樣的話,我們應該(A)在這裏看到更多的代碼,並且(b)還應該假設_counter改變了它的值其他部分也是。 – Jonno

+0

啊我有多愚蠢,不考慮事件在檢查後進入方法的場景:(所以無論我的解決方案是什麼,我需要獨立跟蹤完成,然後只有在我的獨立測試成功後才進行。 – Akuma

1

你有沒有想過一個簡單的同步工作項目隊列?所以當事件發生時,它只是將處理排隊,並且處理按順序由單獨的線程完成?

+0

不知道這是如何幫助,除非你能詳細說明,因爲我需要推遲進行,直到它是適當的,問題是我現在該如何進行。我現在要根據Jonno的迴應來實現一些東西(因爲截止日期尚未結束),除非有更簡單的事情發生。 – Akuma

+0

在一個單線程模型中,你說它工作正常,大概你有一個機制來解決事件是最後被觸發的時間。如果您在工作項目中使用相同的邏輯,以確定它是否應該執行處理,則可以像處理單個線程一樣對待它。實際上,您將多個線程引發的事件彙集到一個同步隊列中,以便您可以將它視爲單個線程。我承認我可能衝過那個答案,所以我猜你確實希望處理位是異步的,但其餘的不是? – blaaaaaaah