我的应用程序中有后台线程,它使用互斥量,如下所示:
void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
MyMutex.MuImageLock.WaitOne();
foreach (var file in ImageFiles)
{
SyncFileToLocalImage(file.FileNameNoPath);
}
MyMutex.MuImageLock.ReleaseMutex();
}同步大约需要2-3分钟。现在我的应用程序中又多了一个后台线程,它们做同样的事情只是为了确保。
我的问题是,在我开始我的第二个线程之前,我想检查互斥是否可用。如果它不可用,这意味着另一个线程正在运行,那么我不需要启动这个新线程。所以使用下面的代码来检查我。
但是使用下面的代码,WaitOne方法会阻塞我的UI线程,直到前一个线程不释放互斥锁。
if (MyMutex.MuImageLock.WaitOne())
{
getPRImages();
MyMutex.MuImageLock.ReleaseMutex();
}我不想阻塞当前的UI线程,我只想看看互斥是否可用。我该怎么做呢?
发布于 2015-02-03 13:05:43
在您的代码示例中,除了后台线程本身,您似乎没有使用BackgroundWorker的任何特性。因此,正确的方法是简单地保留一个标志,并使用Task.Run()启动后台进程:
private bool _isRunning;
private async void Button_Click(object sender, RoutedEventArgs e)
{
if (_isRunning)
{
return;
}
_isRunning = true;
await Task.Run(() => SyncAllFiles());
_isRunning = false;
// Populate ListBox here
}
private void SyncAllFiles()
{
foreach (var file in ImageFiles)
{
SyncFileToLocalImage(file.FileNameNoPath);
}
}注意:在上面的代码中,我假设有一些UI按钮可以启动同步。不幸的是,您的问题没有包含足够完整的代码示例来理解上下文。假设,如果不是一个按钮,您可以调整以上内容以适应您的特定场景。
即使您正在报告进度,只是碰巧在您的问题的代码示例中遗漏了这一点,您仍然可以执行上述操作。只需使用Progress类,将该类的一个实例传递给SyncAllFiles()方法并调用IProgress<T>.Report()方法来实际报告进度。这将与BackgroundWorker.ProgressChanged事件的工作方式相同,因为事件处理程序将在UI线程上调用(只要您在UI线程上创建Progress<T>对象)。
请注意,比上面更好的做法是禁用按钮或其他允许用户再次启动操作的UI元素,只有在操作完成时才重新启用它。
最后:我不认为有一种实用的方法来使用Mutex类(您在帖子中没有具体说明,但我假设您使用的是System.Threading.Mutex)。依赖于互斥锁来协调操作,而UI线程看起来就像是在请求难以解决的竞争条件。例如,如果你的按钮上有两个连续的点击事件,在后台线程可以启动并获取互斥之前处理第二个事件会怎么样呢?这只是它可能出错的许多可能方式之一。
上面提出的解决方案,由于完全在单个线程中管理状态,将确保直接解决所有竞争条件。
https://stackoverflow.com/questions/28279939
复制相似问题