ReaderWriterLockSlim对几个方法的EnterReadLock(),一个在BackgroundWorker中运行

时间:2015-09-22 15:13:08

标签: c# multithreading winforms locking backgroundworker

在我的应用程序中,我使用ReaderWriterLockSlim来同步对list<>的读写操作。

在下面的示例中,读取列表是在所有3个子方法中执行的,因此这3个应该打包到ReadLock中。问题是SubMethod3是通过BackgroundWorker调用的(因为它包含冗长的计算),因此在调整了SubMethod3之前,可能会调用MainMethod1的finally块中的ExitReadLock()。 {1}}(单独的线程)。因此,BackgroundWorker中的代码实际上不受锁的保护。

我考虑的是在每个子方法中使用一个锁,因此SubMethod3将拥有自己的锁,这将在Submethod3完成时释放。这种方法的问题是另一个线程可以在子方法的调用之间进入,因为每个方法都会在完成时释放锁。

我的问题是:BackgroundWorker如何用来保护更多线程?

ReadLock

1 个答案:

答案 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)是最简单的,如果你能负担得起(如果SubMethod1SubMethod2不需要在UI上运行线程或可以编组必要的调用)。