臨界區(如Window的互斥體)用於互斥:只允許單個線程進入代碼路徑。
但是,這不是你想要做的事情:你需要的東西會告訴你是否有事情發生。
一個更好的方法將是一個手動復位事件:設置(也稱爲信號)在任務開始和結束時復位。然後,您可以通過等待正常Window事件的超時值爲零,或使用適用於其他類型事件的成員來檢查它是否通過信號發送。
由於這似乎都在一個單一的過程中,一個好的起點是System.Threading.ManualRestEventSlim
。使用類似於:
// One off initialisation somewhere at class scope
private static ManualResetEventSlim taskRunning = new ManualResetEventSlim();
private static object taskLock = new Object();
// code called from the timer, do in a lock to avoid race conditions with two
// or more threads call this.
lock (taskLock) {
if (!taskRunning.IsSet) {
StartTheTask(); // assuming this does not return until task is running.
}
}
// At the outermost scope of the code in the task:
try {
Debug.Assert(!taskRunning.IsSet); // Paranoia is good when doing threading
taskRunning.Set();
// Task impementation
} finally {
Debug.Assert(taskRunning.IsSet); // Paranoia is good when doing threading
taskRunning.Reset();
}
另一種方法是始終啓動任務,但讓它檢查事件,如果設置則立即退出。這仍然需要lock
來避免在線程間調用IsSet
和Set()
之間的比賽。第二種方法將檢查代碼保存在一起,代價是簡單地運行另一個任務(除非這很常見,否則我可能會將此方法用於代碼局部性)。
你的代碼不是線程安全的,它是一個種族。 –
@SriramSakthivel:你的意思是在繼續使用block和IsEntered的版本之間存在競爭?但是如果SynchronizationContext是相同的,怎麼會有一場比賽呢? – JonPall