2015-09-22 55 views
0

在我的應用程序中,我使用ReaderWriterLockSlim來同步來自list<>的讀寫操作。ReaderWriterLockSlim EnterReadLock()通過幾個方法運行,其中一個在BackgroundWorker中運行

在以下示例中,讀取列表是在所有3個子方法內執行的,因此這3個應打包爲ReadLock。問題在於SubMethod3是通過BackgroundWorker調用的(因爲它包含冗長的計算),所以在MainMethod1的finally塊中的ExitReadLock()可能在子方法3由BackgroundWorker(獨立線程)完成之前調用。因此SubMethod3中的代碼並不真正受鎖的保護。

我考慮過的是在每個子方法中使用一個鎖,所以Submethod3會有自己的鎖,當BackgroundWorker完成時會釋放鎖。這種方法的問題是另一個線程可能會在子方法的調用之間進入,因爲每個線程都會在完成時釋放鎖。

我的問題是:ReadLock如何用於保護更多的線程?

ReaderWriterLockSlim synchronizationLock = new ReaderWriterLockSlim(); 

public void MainMethod1() 
    { 
     synchronizationLock.EnterReadLock(); 
     try 
     { 
      SubMethod1(); //Run on UI thread 
      SubMethod2(); //Run on UI thread 
      myBackgroundWorker.RunWorkerAsync(); 
     } 
     finally 
     { 
      synchronizationLock.ExitReadLock(); 
     } 
    } 


private void myBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
     { 
      SubMethod3(); //Run on separate thread 
     } 
+0

嗯,不,你從MainMethod1()調用SubMethod3。如果你還*從BGW調用它,那麼它必須全部使用* synchronizationLock *。 –

+0

好的,我更新了這個問題,以便更清楚我已經在做什麼。 – JohnSaps

+0

@ downvoter:爲什麼?問題不清楚,還是我完全失望?沒有評論,沒有人會變得更聰明。 – JohnSaps

回答

2

一般來說,你運氣不好。由於線程關聯性,您不能從另一個線程釋放鎖。如果您嘗試持有讀寫器鎖(意識到這將允許工作人員獲取其自己的讀鎖),並等待工作線程啓動,請獲取讀寫器鎖並通知您,以便您可以釋放讀鎖那個時候,如果由於ReaderWriterLock(Slim)實施的讀者/服務員公平性而出現等待寫作者線程,則所有你會得到的將是死鎖。

我看到如下選項:

(A)運行在一個單獨的線程的整個MainMethod1。 (B)編寫並使用您自己的支持此類場景的讀寫器鎖實現。

(C)擺脫BackgroundWorker並切換到使用這裏所描述的AsyncReaderWriterLock實現的一個async/await實施ReaderWriterLockSlim and async\await

(d)因爲我已經注意到了評論Run on UI thread,只有且僅當該方法使用支持從另一個線程編組電話(這是WF和WPF UI線程真)螺紋,可以使用以下方法:

public void MainMethod1() 
{ 
    synchronizationLock.EnterReadLock(); 
    bool releaseLock = true; 
    try 
    { 
     SubMethod1(); 
     SubMethod2(); 
     RunWorkerCompletedEventHandler onRunWorkerCompleted = null; 
     onRunWorkerCompleted = (sender, e) => 
     { 
      ((BackgroundWorker)sender).RunWorkerCompleted -= onRunWorkerCompleted; 
      synchronizationLock.ExitReadLock(); 
     }; 
     myBackgroundWorker.RunWorkerCompleted += onRunWorkerCompleted; 
     myBackgroundWorker.RunWorkerAsync(); 
     releaseLock = false; 
    } 
    finally 
    { 
     if (releaseLock) 
      synchronizationLock.ExitReadLock(); 
    } 
} 

請注意不是同時選項(d)似乎解決了這個問題上下文MainMethod1,如果UI線程試圖從另一個地方獲取讀鎖,並且存在正在等待的編寫器,它很容易導致死鎖。

通常使用UI線程長時間保持鎖定是一個壞主意,會導致更多問題而不是解決問題。 IMO最好的選項是(A)和(C),到目前爲止(A)是最簡單的,如果你負擔得起的話(如果SubMethod1SubMethod2不需要在UI線程上運行,或者可以將必要的調用它)。

+0

感謝您的回答!這在歐洲已經很晚了,所以明天早上我會仔細研究一下。 – JohnSaps

+0

John,我要更新它,請不要在此之前檢查它。 –

+0

回答更新,希望有所幫助。 –

相關問題