C# ReaderWriterLockSlim EnterReadLock()超过几个方法,其中一个在BackgroundWorker中运行
在我的应用程序中,我使用一个C# ReaderWriterLockSlim EnterReadLock()超过几个方法,其中一个在BackgroundWorker中运行,c#,multithreading,winforms,locking,backgroundworker,C#,Multithreading,Winforms,Locking,Backgroundworker,在我的应用程序中,我使用一个ReaderWriterLockSlim来同步从列表进行的读写操作 在下面的示例中,读取列表是在所有3个子方法中执行的,因此这3个子方法应该打包到ReadLock中。问题是BackgroundWorker调用SubMethod3(因为它包含冗长的计算),因此在BackgroundWorker(单独线程)完成SubMethod3之前,可能会调用main方法1的最后一个块中的exitradlock()。因此,子方法3中的代码实际上不受锁的保护 我考虑的是在每个子方法中使用
ReaderWriterLockSlim
来同步从列表
进行的读写操作
在下面的示例中,读取列表是在所有3个子方法中执行的,因此这3个子方法应该打包到ReadLock
中。问题是BackgroundWorker
调用SubMethod3
(因为它包含冗长的计算),因此在BackgroundWorker
(单独线程)完成SubMethod3之前,可能会调用main方法1的最后一个块中的exitradlock()
。因此,子方法3
中的代码实际上不受锁的保护
我考虑的是在每个子方法中使用一个锁,因此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
}
总的来说,你运气不好。由于线程相关性,您无法从另一个线程释放锁。如果您试图保持读卡器锁(这将允许工作线程获取自己的读锁),并等待工作线程启动,则获取读卡器锁并通知您,以便您可以在此时释放读锁,如果由于
ReaderWriterLock(Slim)
实现的reader/water公平性,有一个等待的writer线程,那么您将得到一个死锁
我看到以下选项:
(A) 在单独的线程上运行整个main方法1
(B) 编写并使用您自己的读写器锁实现来支持这种场景
(C) 摆脱BackgroundWorker
并使用此处描述的AsyncReaderWriterLock
实现之一切换到async/await
实现
(D) 由于我注意到UI线程上运行的注释,,仅当且仅当支持封送来自另一个线程的调用的线程使用该方法时(对于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)似乎在main方法1
的上下文中解决了该问题,但如果UI线程试图从另一个位置获取读取锁,并且有一个挂起的写入程序等待,则很容易导致死锁
一般来说,从UI线程使用长时间保持锁是一个坏主意,它会导致更多问题,而不是解决问题。在我看来,最好的选项是(A)和(C),到目前为止(A)是最简单的,如果你负担得起的话(如果SubMethod1
和SubMethod2
不需要在UI线程上运行,或者可以对其进行必要的调用)。Hmm,不,你是从MainMethod1()调用SubMethod3。如果您也从BGW调用它,那么它必须单独使用synchronizationLock。好的,我更新了这个问题,以便更清楚地说明我已经在做什么。@downvoter:为什么?这个问题不清楚,还是我完全错了?没有评论,没有人会变得更聪明。(如果有评论的话,可以询问反对票,尽管根据我的经验,投票人已经离开了,所以这样做没有太大价值。但是我们确实要求不要在帖子中添加这样的评论,因为绝大多数未来读者对这些评论不感兴趣,如果你把它们放进去,人们有时会投反对票)@halfer:好的,谢谢。你能向我解释一下为什么这个问题被否决了吗?即使在你编辑了它之后?没有解释,我也不知道该修改什么,或者将来如何描述这些问题。谢谢你的回答!欧洲已经很晚了,所以我明天早上会仔细研究。约翰,我要更新它,请更新在那之前不要回顾。我最终以不同的方式重写了我的程序,因此这不再是一个问题。我没有设法将你的任何建议应用到我的案例中,但还是非常感谢!