老問題,我知道,但是我想把它扔給那些絆倒它的人。
C#(大概是VB.NET)爲處理線程同步提供了一些不錯的選擇。您可以使用lock
關鍵字來阻止執行,直到給定鎖定可用;或者,如果要指定用於取得鎖定的超時(可能立即),則使用Monitor.TryEnter()
。
對於這些方法中的任何一種,都需要一個用於鎖定的對象。幾乎任何對象都會做;如果你不同步訪問某個對象本身(集合,數據庫連接,無論),你甚至可以實例化一次性的object
。對於輪詢定時器,後者是典型的。
首先,確保你有一個對象用於同步:現在
public class DatabasePollingClass {
object PollingTimerLock = new object();
...
,如果你想輪詢線程阻塞無限期地等待輪到自己,用lock
關鍵字:
public class DatabasePollingClass {
object PollingTimerLock = new object();
...
protected void PollingTimerCallback() {
lock (PollingTimerLock) {
//Useful stuff here
}
}
}
一次只允許一個線程在lock (PollingTimerLock)
代碼塊內。所有其他線程將無限期地等待,然後一旦它們可以獲取自己的鎖,就可以繼續執行。
但是,你可能不希望這種行爲。如果您希望後續線程立即中止(或稍後等待),如果另一個輪詢線程仍在運行,則在鎖定時可以使用Monitor.TryEnter()
。這確實需要稍微謹慎,但是:
public class DatabasePollingClass {
object PollingTimerLock = new object();
...
protected void PollingTimerCallback() {
if (Monitor.TryEnter(PollingTimerLock)) { //Acquires lock on PollingTimerLock object
try {
//Useful stuff here
} finally {
//Releases lock.
//You MUST do this in a finally block! (See below.)
Monitor.Exit(PollingTimerLock);
}
} else {
Console.WriteLine("Warning: Polling timer overlap. Skipping.");
}
}
}
額外小心從不像lock
關鍵字,Monitor.TryEnter()
需要你,當你用它完成手動解除鎖定的事實造成的。爲了確保發生這種情況,您需要將整個關鍵部分包裝在try
區塊中,並釋放finally
區塊中的鎖定。這是爲了確保鎖定將被釋放,即使輪詢方法失敗或提前返回。如果該方法在未釋放鎖的情況下返回,則您的程序將被有效掛起,因爲沒有其他線程能夠獲取該鎖。
另一個不使用鎖定機制的選項是配置你的定時器而不需要重複週期,即一次性定時器。在輪詢方法結束時,您將丟棄舊的定時器,並設置一個新的定時器(您還需要在finally
塊內執行此操作,以確保定時器在方法結束時被重置)。如果您想要在先前輪詢的結束以來的某個時間間隔輪詢數據庫,此方法將非常有用。這是一個微妙的區別,但它也解決了併發輪詢嘗試的問題。
請注意,這是一個真的簡單線程併發示例。只要所有的鎖定都是在與UI線程分開的線程上發生的(消息泵本身可能成爲爭用的焦點),並且您只鎖定了一個對象,那麼您不必過多擔心死鎖。那些調試真的很不愉快;症狀通常是「應用程序停止響應,現在您可以猜測哪些線程正在等待什麼」。
來源
2014-03-19 14:13:36
db2
依靠數據庫和網絡鎖定的問題是什麼?鎖定記錄的最佳方式是鎖定記錄。 – Paparazzi