2010-09-21 85 views
1

我不太清楚如何詞這一點,所以我就貼上我的代碼,並提出這樣的問題:鎖定傳遞給其他線程的對象會發生什麼?

private void remoteAction_JobStatusUpdated(JobStatus status) { 
    lock (status) { 
     status.LastUpdatedTime = DateTime.Now; 
     doForEachClient(c => c.OnJobStatusUpdated(status)); 
     OnJobStatusUpdated(status); 
    } 
} 

private void doForEachClient(Action<IRemoteClient> task) { 
    lock (clients) { 
     foreach (KeyValuePair<RemoteClientId, IRemoteClient> entry in clients) { 
      IRemoteClient clientProxy = entry.Value; 
      RemoteClientId clientId = entry.Key; 
      ThreadPool.QueueUserWorkItem(delegate { 
       try { 
        task(clientProxy); 
#pragma warning disable 168 
       } catch (CommunicationException ex) { 
#pragma warning restore 168 
        RemoveClient(clientId); 
       } 
      }); 
     } 
    } 
} 

假設其修改status對象的任何其他代碼將在首先獲得鎖。

由於status對象是通過傳遞一路多ThreadPool線程,以及調用ThreadPool.QueueUserWorkItem將前實際完成的任務完成,我會確保同一status對象被髮送到所有客戶端?

換句話說,lock (status)語句何時「過期」或導致其鎖被釋放?

回答

5

鎖不要失效。當一個線程試圖通過lock語句時,它只能在lock狀態塊中使用該特定對象實例上的一個lock塊內沒有執行其他線程時執行此操作。

在你的情況,似乎你有一個主線程執行。它將鎖定statusclients實例,然後它將在單獨執行的線程上執行新任務。如果新線程中的任何代碼想要獲取statusclients上的鎖,則必須等到主線程通過保留兩個lock塊來釋放兩個鎖。當remoteAction_JobStatusUpdated返回時會發生這種情況。

您將status對象傳遞給每個工作線程,並且它們都可以隨意執行他們想要對該對象執行的任何操作。聲明lock (status)絕不保護status實例。但是,如果任何線程試圖執行lock (status),它們將阻塞,直到主線程釋放鎖。

使用兩個單獨的對象實例進行鎖定可能會導致死鎖。假設一個線程執行以下代碼:

lock (status) { 
    ... 
    lock (clients) { 
    ... 
    } 

}

另一線程執行下面的代碼,其中所述鎖被以相反的順序獲取的:

lock (clients) { 
    ... 
    lock (status) { 
    ... 
    } 

}

如果第一個線程設法首先獲得狀態,第二個線程先鎖定它們,然後兩個線程將不再運行。

一般來說,我會建議你去把你的共享狀態在一個單獨的類,並獲得線程安全:

class State { 

    readonly Object locker = new Object(); 

    public void ModifyState() { 
    lock (this.locker) { 
     ... 
    } 
    } 

    public String AccessState() { 
    lock (this.locker) { 
     ... 
     return ... 
    } 
    } 

} 

您還可以標記你的方法與[MethodImpl(MethodImpl.Synchronized)]屬性,但它有它的缺陷因爲它將用一個不推薦的lock (this)包圍該方法。

如果您想更好地瞭解lock聲明背後的情況,可以閱讀MSDN雜誌中的Safe Thread Synchronization文章。

+0

編輯這個問題,希望能夠澄清我的措辭。我忘了說任何修改我的'status'對象的其他代碼將首先獲取它的鎖。無論如何,這回答我的問題,謝謝。 – jnylen 2010-09-21 14:34:48

+0

一個問題,但是:你說「你不能將鎖傳遞給其他線程。」但作爲一個人爲的例子,說我做了'lock(someObject){Thread t = new Thread(new ThreadStart(doSomething)); t.Start(); t.Join(); }'那麼鎖就會被有效地傳遞給我的另一個線程,因爲它會一直保持線程運行的整個時間,對吧? – jnylen 2010-09-21 14:42:27

+0

@jnylen:我刪除了你從我的回答中引用的文字,因爲它沒有什麼意義。關於你的例子:只要新線程不嘗試「鎖定(someObject)」,答案是肯定的。否則,你有一個死鎖,兩個線程都被阻塞,等待另一個線程。 – 2010-09-21 15:07:48

0

鎖確實不會自動「過期」,鎖將有效直到鎖(..){}語句的右大括號。

+0

「過期」是一個糟糕的選擇。 – jnylen 2010-09-21 14:34:12

相關問題