我有一個對象,一次只能由一個線程使用。 例如,如果一個線程訪問方法A
,我的對象包含3個方法A
,B
和C
,我想鎖定對象(所有方法/屬性都被鎖定)。C#阻止從其他線程訪問所有對象方法
主要難點是我無法修改該對象的代碼。我必須防止多線程訪問我調用對象。
我的第一個想法是使用單例模式,但我沒有設法使它工作!
我有一個對象,一次只能由一個線程使用。 例如,如果一個線程訪問方法A
,我的對象包含3個方法A
,B
和C
,我想鎖定對象(所有方法/屬性都被鎖定)。C#阻止從其他線程訪問所有對象方法
主要難點是我無法修改該對象的代碼。我必須防止多線程訪問我調用對象。
我的第一個想法是使用單例模式,但我沒有設法使它工作!
如果無法更改對象的代碼,則必須處理鎖定以外的對象。例如,你可以將其封裝在另一個類(也許隱藏在接口後面),並有包裝類應用同步:
public class Foo {
private readonly YourType tail;
private readonly object syncLock = new object();
public Foo(YourType tail) {this.tail = tail;}
public A() { lock(syncLock) { tail.A(); } }
public B() { lock(syncLock) { tail.B(); } }
public C() { lock(syncLock) { tail.C(); } }
}
謝謝至少有2人注意到這不是另一個問題的完全重複! – darkheir 2012-08-14 09:32:52
Singleton模式是不是在這裏是正確的 - 它可以確保只有有一個對象的單個實例,但並不指定如何使用它。
代碼中的線程安全性必須在代碼中定義。也就是說,如果你不能修改你的對象的代碼,你將無法正確地線程安全。但是,有一種解決方法:您可以將對象包裝在您創建的新類中,並確保您的新對象爲線程安全。通過爲你的不安全對象的方法公開線程安全的包裝器,你可以確保它以你想要的方式訪問。
最簡單的方法是使用lock
關鍵字。像這樣的東西可能會奏效:
public class ThreadSafeThing
{
private UnsafeThing _thing = new UnsafeThing();
private object _syncRoot = new object();
public void DoSomething() // this is your thread-safe version of Thing.DoSomething
{
lock (_syncRoot)
{
_thing.DoSomething();
}
}
}
假設你不能只是建立每個線程一個對象,另一種方式是提高一個多線程調用非線程對象的方法,然後排隊呼叫請求那一個線程。通常,線程應該在排隊的請求中執行對非線程安全對象的請求操作後觸發'OnCompletion'回調。
然後異步執行操作,但可以通過排隊請求然後等待回調信號發出的事件來進行同步呼叫。
..只是另一種可能比在包裝對象中簡單鎖定更靈活。
OP沒有指定,但是如果他的scenerio包含他需要保持跨多個客戶端調用鎖定對象的可能性(例如他需要從客戶端調用函數A,那麼根據結果調用函數B或C,保持對象鎖定到其他線程的整個時間),你需要不同的方式實現了一下,例如:
public static class ThreadSafeThing {
private static UnsafeThing _thing = new UnsafeThing();
private static readonly object _lock = new object();
public static void getLock() {
Monitor.Enter(_lock);
}
public static void releaseLock() {
Monitor.Exit(_lock);
}
// this is your thread-safe version of Thing.DoSomething
public static bool DoSomething() {
try {
Monitor.Enter(_lock);
return _thing.DoSomething();
}
finally {
Monitor.Exit(_lock);
}
}
// this is your thread-safe version of Thing.DoSomethingElse
public static void DoSomethingElse() {
try {
Monitor.Enter(_lock);
return _thing.DoSomethingElse();
}
finally {
Monitor.Exit(_lock);
}
}
}
從像這樣的客戶電話...
try {
ThreadSafeThing.getLock();
if (ThreadSafeThing.DoSomething()) {
ThreadSafeThing.DoSomethingElse();
}
}
finally {
// This must be called no matter what happens
ThreadSafeThing.releaseLock();
}
的這裏的主要區別是客戶負責一旦完成,獲得一個鎖並釋放它。這允許在維持鎖的同時調用對象上的多個函數。所有其他線程將在getLock調用上阻塞,直到鎖使用releaseLock釋放。
編輯:在DoSomething和DoSomethingElse方法中添加了自動獲取鎖定,如果直接調用這些方法而不通過getLock方法獲取鎖定,則線程也可以獲得一次性鎖定。但是,應該注意的是,如果鎖是通過這種方式獲得的,它只會持續單個方法調用。
http://stackoverflow.com/questions/1344025/how-to-make-a-class-thread-safe – Freeman 2012-08-14 09:20:03
使用鎖定(this){// ur functions} – Moons 2012-08-14 09:24:29
@Freeman:相關的,但不完全是因爲海報不能修改他們課程的代碼。 – 2012-08-14 09:25:12