[英]Best Practices in using a lock
假設我在某個類中有以下屬性,其目的是用作鎖。
protected object SyncRoot { get; private set; }
無論如何,無論如何以及是否設置。 如果實際上已設置,那么使用它的最佳實踐是什么?
由於鎖定不適用於空對象,我應該像這樣處理它嗎?
lock (SyncRoot ?? new object())
SomeMethod();
或者我應該像這樣檢查 null 嗎?
if (SyncRoot != null)
lock (SyncRoot)
SomeMethod();
else
SomeMethod();
如果它是,事實上,設置,我想用它來鎖定。 否則,我不在乎。 無論如何,第一個解決方案效率低下還是多余?
編輯:所有這些答案都很好。 但是,我只能選擇一個。 鑒於我與 Luke 討論的情況,我的 SyncRoot 沒有理由應該為空。 在單線程環境中鎖的開銷並不大,但如果在多線程環境中是必要的。
(為所有 4 人投票)感謝大家的快速回復。
我通常使用私有成員變量而不是屬性,即
private static object MyLock = new object();
這樣它總是被初始化。
您還可以使用非靜態版本,例如
private readonly object MyLock = new object();
同步於
SyncRoot ?? new object()
沒有意義,因為如果SyncRoot
為null
,則每個線程每次都會獲得一個新對象。 在單獨的對象上同步沒有效果:線程將立即繼續,因為沒有其他人可能在同一個new
對象上同步。
在第一個線程嘗試獲取鎖之前,您應該在構造函數中初始化SyncRoot
。
第一個將是一個問題,因為它不會導致任何良好的同步:
lock (SyncRoot ?? new object())
SomeMethod();
原因是如果您創建一個新對象而不將其分配給SyncRoot
,它將被放置在堆上,但不會有對它的引用。 所以當另一個線程來的時候,它不會找到它......它變得絕對沒用,它不會阻止對臨界區的任何訪問。
第二種方法會起作用,但我真的不明白為什么你想使用鎖,如果它只可用。
來自文檔: https : //msdn.microsoft.com/en-us/library/c5kehkcz.aspx
通常,避免鎖定公共類型或超出代碼控制范圍的實例。 常見的構造 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 違反了此准則:
- 如果可以公開訪問實例,則鎖定(此)是一個問題。
- 如果 MyType 可公開訪問,則 lock (typeof (MyType)) 是一個問題。
- lock("myLock") 是一個問題,因為進程中使用相同字符串的任何其他代碼都將共享相同的鎖。
最佳實踐是定義要鎖定的私有對象,或定義私有靜態對象變量來保護所有實例共有的數據。
樣本:
class Account
{
decimal balance;
private Object thisLock = new Object();
public void Withdraw(decimal amount)
{
lock (thisLock)
{
if (amount > balance)
{
throw new Exception("Insufficient funds");
}
balance -= amount;
}
}
}
最好的選擇是在鎖對象的任何使用者有機會使用它之前始終初始化鎖對象。 一直分配鎖對象的開銷小,沒有線程爭用時拿鎖的開銷小。
因此,在您的代碼中添加鎖/無鎖檢查將使您的代碼復雜性加倍,並且可能會引入微妙的線程錯誤,但可能不會產生任何切實的性能優勢。
簡化你的代碼:總是拿鎖。
如果需要對隊列、集合和字典等對象進行線程安全訪問,我會鎖定該對象本身,不需要單獨的鎖定對象。 最好是隊列、集合或字典是私有的或只讀的,這樣您就可以確保它們始終是同一個對象。
樣本:
class Processor
{
readonly Queue<int> processQueue = new Queue<int>();
public void AddToQueue(int index)
{
lock (processQueue)
{
processQueue.Enqueue(index);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.