2011-04-05 62 views
2

c#中是否存在類似於lock {}的構造,但在從事件處理程序調用時工作,即在處理後續事件之前等待代碼塊完成。C#從事件中鎖定

我遇到的問題是鎖只阻止其他線程獲取對象上的鎖,但是如果同一線程上的事件處理程序被調用,鎖塊內代碼的執行將被中斷,並且在返回執行原始代碼之前處理新事件。

object DoStuffLock = new object(); 

public void DoStuff() 
{ 
    lock (DoStuffLock) 
    { 
     // Do stuff that we don't want to be interrupted, 
     // but because it is called from an event handler 
     // it still can be interrupted despite the lock 
    } 
} 

目前我周圍像這樣的問題,工作(但很難理想):

object DoStuffLock = new object(); 

// this gets called from an event, and therefore can be interrupted, 
// locking does not help, so launch separate thread 
public void DoStuff() 
{ 
    var x = new Thread(DoStuffInternal); 
    x.Start(); 
} 

private void DoStuffInternal() 
{ 
    lock (DoStuffLock) 
    { 
     // Do stuff that we don't want to be interrupted 
    } 
} 
+0

線程不能被事件「中斷」。你還沒有診斷出真正的問題。 – 2011-04-05 20:06:08

+0

確實 - 你是對的 - 我沒有診斷出真正的問題。 – 2011-04-05 20:47:57

回答

3

我遇到的問題是,鎖定{}只是阻止其他從獲得線程鎖定對象,但是如果同一線程上的事件處理程序被調用

這真的不會發生。如果您的線程正在執行,則在同一線程上不會發生事件 - 必須在不同的線程中引發該事件。

這就是說,在任何情況下,你的「第二種方法」在許多方面都是優越的。有一個隱含的假設,事件處理程序將很快返回。 「阻塞」事件處理程序通常是設計不好的標誌,並且可能會導致問題,特別是因爲事件發佈者不會期望事件被阻止。

+0

有問題的事件由FileSystemWatcher觸發,並且DoStuff()中的代碼非常快速地返回。儘管如此,如果FileSystemWatcher以非常快的速度連續觸發多個事件(並且經常這樣做),DoStuff()中的代碼會被中斷以處理新事件。 – 2011-04-05 19:42:54

+0

@Mthethew:你可以在沒有單獨線程的情況下執行鎖定。 FileSystemWatcher在線程池線程上引發事件 - 所以你的鎖在那裏工作的很好。它永遠不會在同一個線程中引發它,因爲你的代碼正在執行。因此,它永遠不會中斷你的代碼 - 它可能同時運行2個副本(這使得調試器看起來像是中斷,但檢查線程窗口..)。如果這不可取,則方法中的鎖將保護它而不需要單獨啓動線程。 – 2011-04-05 19:45:16

+0

你當然是正確的 - 問題存在於其他地方 - 並且在單獨的線程中運行鎖定代碼似乎是通過延遲執行來「解決」問題 - 感謝堅持認爲我錯了,並讓我重新檢查了所有內容時間。 – 2011-04-05 20:46:42

0

想想鎖定代碼,而不是對象。

使用相同的鎖對象鎖定無法同時輸入的代碼段。

此外,鎖不停止中斷,它們只是同時停止從2個線程訪問同一段代碼。

0

UI事件都是從同一個線程調用的。鎖旨在保護多線程。鎖專門設計爲允許同一個線程多次調用同一個鎖,否則會發生死鎖。

我認爲你的第二個解決方案是正確的。如果你有一段代碼必須在一個塊中執行,那麼你在一個新的線程上執行它。

0

在Windows等操作系統中,您無法對事件處理的順序作出任何假設。只有使用實時操作系統才能完成此操作。

你可以做你的情況是你可以增加你的線程優先級。這應該給你的線程更多的時間(相對於其他線程)。有關.net中的線程優先級的更多信息,請訪問:http://msdn.microsoft.com/en-us/library/system.threading.threadpriority.aspx