在DoWork中与ShowDialog一起使用Control.Invoke时,BackgroundWorker死锁

时间:2013-01-23 09:18:37

标签: c# winforms backgroundworker deadlock invoke

我在BackgroundWorker中运行了一项长任务,通过ReportProgress更新了用户界面。但是,在进程的中间,我需要进行COM调用以获取一些数据,我想我需要在UI线程上进行。我试过通过Control.Invoke这样做。但是,我陷入僵局。不能在Control.InvokeBackgroundWorker)中使用ShowDialog吗?

我试图简化代码:

        var log = new LogWindowForm();
        worker.DoWork += (sender, args) =>
        {
                creator.LogProgress = (s, i) => worker.ReportProgress(i,s);
                creator.GetMoreDataFunc = (s) => InvokeGetMoreDataOnGuiThread(log, s);
                ...
                var data = GetMoreDataFunc("id:"+id)
        };
        worker.RunWorkerAsync();
        log.ShowDialog();


    private Dictionary<string, string> InvokeGetMoreDataOnGuiThread(Control invokeControl, string id)
    {
        var data = new Dictionary<string, string>();
        Action action = () => data = GetMoreDataFromComObject(mainComObject, id);
        invokeControl.Invoke(action); // deadlock!
        return data;
    }

编辑:

没有例外,UI不断更新,但它会停止进展。 Break All显示Control.Invoke调用中的工作线程和ShowDialog调用中某处的GUI线程。

GUI线程似乎在消息循环中:

System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason,System.Windows.Forms.ApplicationContext context)+ 0x65 bytes

我猜这就是UI不断更新的原因。 BackgroundWorker中是否有一些锁定?

1 个答案:

答案 0 :(得分:0)

猜测,因为我不知道COM对象的作用或要求:

COM对象需要UI htread的原因可能是因为(在大多数情况下)UI线程被标记为STA线程。

如果COM对象需要单线程公寓,则可以使用标记为STA线程的非UI线程。这样你就不再声称UI线程了。

请参阅:Could you explain STA and MTA?

和:an explanation of STA in .NET

How to make a .NET thread STA or MTAby using an attribute