2012-08-14 92 views
3

我有一個對象,一次只能由一個線程使用。 例如,如果一個線程訪問方法A,我的對象包含3個方法ABC,我想鎖定對象(所有方法/屬性都被鎖定)。C#阻止從其他線程訪問所有對象方法

主要難點是我無法修改該對象的代碼。我必須防止多線程訪問我調用對象。

我的第一個想法是使用單例模式,但我沒有設法使它工作!

+4

http://stackoverflow.com/questions/1344025/how-to-make-a-class-thread-safe – Freeman 2012-08-14 09:20:03

+0

使用鎖定(this){// ur functions} – Moons 2012-08-14 09:24:29

+2

@Freeman:相關的,但不完全是因爲海報不能修改他們課程的代碼。 – 2012-08-14 09:25:12

回答

9

如果無法更改對象的代碼,則必須處理鎖定以外的對象。例如,你可以將其封裝在另一個類(也許隱藏在接口後面),並有包裝類應用同步:

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(); } } 
} 
+0

謝謝至少有2人注意到這不是另一個問題的完全重複! – darkheir 2012-08-14 09:32:52

5

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(); 
     } 
    } 
} 
0

假設你不能只是建立每個線程一個對象,另一種方式是提高一個多線程調用非線程對象的方法,然後排隊呼叫請求那一個線程。通常,線程應該在排隊的請求中執行對非線程安全對象的請求操作後觸發'OnCompletion'回調。

然後異步執行操作,但可以通過排隊請求然後等待回調信號發出的事件來進行同步呼叫。

..只是另一種可能比在包裝對象中簡單鎖定更靈活。

1

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方法獲取鎖定,則線程也可以獲得一次性鎖定。但是,應該注意的是,如果鎖是通過這種方式獲得的,它只會持續單個方法調用。

相關問題