C# 如何使BackgroundWorker ProgressChanged事件按顺序执行?

C# 如何使BackgroundWorker ProgressChanged事件按顺序执行?,c#,.net,backgroundworker,race-condition,C#,.net,Backgroundworker,Race Condition,考虑以下代码: private static BackgroundWorker bg = new BackgroundWorker(); static void Main(string[] args) { bg.DoWork += bg_DoWork; bg.ProgressChanged += bg_ProgressChanged; bg.WorkerReportsProgress = true; bg.RunWorkerAsync(); Thread.Sleep(10

考虑以下代码:

private static BackgroundWorker bg = new BackgroundWorker();

static void Main(string[] args) {
  bg.DoWork += bg_DoWork;
  bg.ProgressChanged += bg_ProgressChanged;
  bg.WorkerReportsProgress = true;
  bg.RunWorkerAsync();

  Thread.Sleep(10000);
}

static void bg_ProgressChanged(object sender, ProgressChangedEventArgs e) {
  Console.WriteLine(e.ProgressPercentage);
  Thread.Sleep(100);
  Console.WriteLine(e.ProgressPercentage);
}

static void bg_DoWork(object sender, DoWorkEventArgs e) {
  for (int i = 0; i < 10; i++) {
    bg.ReportProgress(i);
  }
}
private static BackgroundWorker bg=new BackgroundWorker();
静态void Main(字符串[]参数){
bg.DoWork+=bg_DoWork;
bg.ProgressChanged+=bg_ProgressChanged;
bg.WorkerReportsProgress=true;
bg.RunWorkerAsync();
睡眠(10000);
}
静态无效bg_ProgressChanged(对象发送方,ProgressChangedEventArgs e){
控制台写入线(如百分比);
睡眠(100);
控制台写入线(如百分比);
}
静态无效bg_DoWork(对象发送方,DoWorkEventArgs e){
对于(int i=0;i<10;i++){
bg.进度报告(一);
}
}
运行时,我得到以下输出:

0 1. 1. 2. 0 3. 2. 3. 5. 4. 4. 6. 5. 7. 7. 8. 6. 9 8. 九,

我知道问题在于BackgroundWorker每次调用ReportProgress时启动的线程之间的争用条件

我如何确保每个bg_ProgressChanged的整个主体按照我调用它们的顺序执行? 那是我想要的

01 12 3 4 5 5 6 7 8 9


因此。

BackgroundWorker
在调用
RunWorkerAsync()的线程的当前同步上下文上引发
ProgressChanged
事件

默认SynchronizationContext在线程池上运行回调,而不进行任何同步


如果您在UI应用程序(WPF或WinForms)中使用BackgroundWorker,它将使用该UI平台的SynchronizationContext,它将按顺序执行回调。

请勿使用此解决方案!!!正如SLaks指出的那样,可能会导致死锁。

我似乎无意中找到了答案。我按以下方式更改了代码:

   [MethodImpl(MethodImplOptions.Synchronized)]
   static void bg_ProgressChanged(object sender, ProgressChangedEventArgs e) {
     Console.WriteLine(e.ProgressPercentage);
     Thread.Sleep(100);
     Console.WriteLine(e.ProgressPercentage);
   }
现在我得到了我想要的输出:

0 0 1. 1. 2. 2. 3. 3. 4. 4. 5. 5. 6. 6. 7. 7. 8. 8. 9 九,


BackgroundWorker实际上不适合在没有UI线程的情况下使用。更喜欢在增量中使用ReportProgress的Ist参数,而不是userState参数。建议您查看此MSDN链接以报告进度:@Vijay谢谢。修复了它。尝试将ReportProgress方法调用包装在一个锁(_-objectLock)块中,例如lock(_-lockObject){bg.ReportProgress(i);}@Vijay:这根本没有任何区别;这些调用在同一个线程上运行。我已经使用目标.NETFramework 3.5创建了一个控制台应用程序示例。我已将输出类型更改为Windows应用程序,其工作方式与您所描述的相同。我的问题是,我希望ProgressChanged事件的整个主体按照我调用它们的顺序执行。我已经更新了这个问题,以更好地反映我想要做的事情。@Andris:在UI同步上下文下,它们将按顺序执行。@SLaks:正如我所说,我已将应用程序输出类型更改为Windows应用程序,但请注意,在我修订的示例中,在输出中,前5个在前4个之前,因此,参数为5的调用在参数为4的调用之前执行。更改输出类型还不够吗?我不确定如何将SynchronizationContext设置为“UI SynchronizationContext”。我不熟悉该主题。您需要通过调用
Application.run()
来运行UI线程。(这是一个阻塞呼叫)。项目类型根本不重要。但是,如果您不使用UI,则可能根本不应该使用BackgroundWorker。在UI应用程序中,这没有什么区别,因为回调将仅在UI线程上运行。请注意,这可能会导致死锁<代码>[MethodImpl(MethodImplOptions.Synchronized)]
相当于
锁定(this)
,不应使用。@SLaks:好提示。再次感谢。