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:好提示。再次感谢。