gpt4 book ai didi

.net - 使用 BackgroundWorker.CancelAsync 时如何避免竞争条件?

转载 作者:行者123 更新时间:2023-12-01 01:19:04 25 4
gpt4 key购买 nike

MSDN article关于 BackgroundWorker.CancelAsync方法,有一个警告说:

Be aware that your code in the DoWork event handler may finish its work as a cancellation request is being made, and your polling loop may miss CancellationPending being set to true. In this case, the Cancelled flag of System.ComponentModel.RunWorkerCompletedEventArgs in your RunWorkerCompleted event handler will not be set to true, even though a cancellation request was made. This situation is called a race condition and is a common concern in multithreaded programming.



避免这种竞争条件的正确和好的解决方案是什么?

这是我的示例代码,它引起了这种情况的出现:
public partial class MainWindow : Window
{
BackgroundWorker bW;
int bWsCount = 0;

public MainWindow()
{
InitializeComponent();
}

private void Window_MouseMove(object sender, MouseEventArgs e)
{
if (bW != null)
bW.CancelAsync();
bW = new BackgroundWorker();
bW.WorkerSupportsCancellation = true;
bW.DoWork += new DoWorkEventHandler(bW_DoWork);
bW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bW_RunWorkerCompleted);
bW.RunWorkerAsync(0);
bWsCount++;
labelBackgroundWorkersCount.Content = bWsCount;
}

void bW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
if (e.Cancelled || worker.CancellationPending)
{
bWsCount--;
labelBackgroundWorkersCount.Content = bWsCount;
}
else
worker.RunWorkerAsync(1000);
}

void bW_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
int sleepDuration = Convert.ToInt32(e.Argument);
if (worker.CancellationPending) { e.Cancel = true; return; }
Thread.Sleep(sleepDuration);
if (worker.CancellationPending) { e.Cancel = true; return; }
}
}

最佳答案

没有办法避免它,不是每个线程问题都有解决方案。当你把它们推到极致时,这些事情可以被推理出来。想象一下,您的 UI 线程中的代码在工作线程完成前一纳秒调用 CancelAsync()。就像线程正在执行它的最后一条机器代码指令一样。显然,线程无法检测到这一点。 UI 线程也没有任何可能的方法来查看线程是否在执行最后一条指令。

这不是一个真正的问题,只需在编写 RunWorkerCompleted 事件处理程序时记住它。如果 e.Cancelled 属性为 false,则工作人员无论如何都完成了。如有必要,您可以简单地将它与另一个在调用 CancelAsync() 时设置为 true 的 bool 一起使用。大致:

    private bool cancelRequested;

private void CancelButton_Click(object sender, EventArgs e) {
cancelRequested = true;
backgroundWorker1.CancelAsync();
}

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (e.Error != null) throw e.Error;
if (!e.Cancelled && !cancelRequested) {
// Completed entirely normally
//...
}
}

请记住,这不仅仅是一场代码竞赛。更实际的问题是,这也是用户大脑中的一场竞赛。在故障模式下,一切正常在用户单击取消按钮前一毫秒完成。

因此,据用户所知,该操作被取消了,而实际上并没有。这可能会产生令人不快的后果,您必须通过告诉用户真正发生的事情来处理这些后果。在这种情况下,使用代码片段确实没有任何意义,如果您只取消操作并允许它完成,它也能正常工作。

关于.net - 使用 BackgroundWorker.CancelAsync 时如何避免竞争条件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10327595/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com