在我的应用程序中,我使用ReaderWriterLockSlim
来同步对list<>
的读写操作。
在下面的示例中,读取列表是在所有3个子方法中执行的,因此这3个应该打包到ReadLock
中。问题是SubMethod3
是通过BackgroundWorker
调用的(因为它包含冗长的计算),因此在调整了SubMethod3之前,可能会调用MainMethod1的finally块中的ExitReadLock()
。 {1}}(单独的线程)。因此,BackgroundWorker
中的代码实际上不受锁的保护。
我考虑的是在每个子方法中使用一个锁,因此SubMethod3
将拥有自己的锁,这将在Submethod3
完成时释放。这种方法的问题是另一个线程可以在子方法的调用之间进入,因为每个方法都会在完成时释放锁。
我的问题是:BackgroundWorker
如何用来保护更多线程?
ReadLock
答案 0 :(得分:2)
一般来说,你运气不好。由于线程关联,您无法从另一个线程释放锁。如果您尝试保持读取器锁定(以为这将允许工作者获取其自己的读锁定),并等待工作线程启动,获取读取器锁定并通知您,因此您可以释放读锁定那个时候,如果由于ReaderWriterLock(Slim)
实现的读者/服务员公平性而存在等待的作者线程,那么你将得到的所有东西都将是一个死锁。
我看到以下选项:
(A)在单独的线程上运行整个 MainMethod1
。
(B)编写并使用支持此类场景的您自己的读/写锁实现。
(C)摆脱BackgroundWorker
并使用此处所述的async/await
实施之一转换为AsyncReaderWriterLock
实施<{3}}
(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)是最简单的,如果你能负担得起(如果SubMethod1
和SubMethod2
不需要在UI上运行线程或可以编组必要的调用)。