为什么我的GUI会冻结?

时间:2014-01-29 17:50:14

标签: wpf debugging user-interface task-parallel-library

我是TPL世界的新手,我做了那段代码:

    var myItems = myWpfDataGrid.SelectedItems;

    this.Dispatcher.BeginInvoke(new Action(() =>
    {
        var scheduler = new LimitedConcurrencyLevelTaskScheduler(5);
        TaskFactory factory = new TaskFactory(scheduler);

        foreach (MyItem item in myItems)
        {
            Task myTask = factory.StartNew(() =>

            DoLoooongWork(item)                   

                ).ContinueWith((t) =>
                {
                    Debug.WriteLine(t.Exception.Message);
                    if (t.Exception.InnerException != null)
                    {
                        Debug.WriteLine(t.Exception.InnerException.Message);
                    }
                },
                TaskContinuationOptions.OnlyOnFaulted);
        }
    }), null);            

唯一访问gui的是“ var myItems = myWpfDataGrid.SelectedItems; ”  它是只读的!函数“DoLoooongWork()”可以访问串行端口等。它是一个独立的SDK函数,不能访问GUI。我知道“Dispatcher.BeginInvoke”有点多余,但我不知道我能做什么,或者我做错了什么。这段代码的唯一原因是在执行“DoLoooongWork()”时释放GUI,但GUI被冻结了!

该代码出了什么问题?

修改

感谢@Euphoric的帮助,我发现了与该帖子类似的问题: COM Interop hang freezes entire COM system. How to cancel COM call

2 个答案:

答案 0 :(得分:3)

我假设DoLoooongWork内的一些对象需要线程亲和力和消息抽取。试试我的ThreadWithAffinityContext,看看是否有帮助,请像这样使用它:

private async void Button_Click(object sender, EventArgs e)
{
    try 
    {           
        using (var staThread = new Noseratio.ThreadAffinity.ThreadWithAffinityContext(
             staThread: true, pumpMessages: true))
        {
            foreach (MyItem item in myItems)
            {
                await staThread.Run(() =>
                {
                    DoLoooongWork(item);
                }, CancellationToken.None);
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

More info about ThreadWithAffinityContext

[更新] 您在评论中提到DoLoooongWork内的代码如下所示:

zkemkeeper.CZKEM axCZKEM1 = new zkemkeeper.CZKEM(); 
axCZKEM1.Connect_Net(ip, port);

之前我从未听说过“zkemkeeper”,但我做了一个简短的搜索,发现this question。显然,Connect_Net只建立连接并启动会话,而整个通信逻辑通过某些事件异步发生,正如该问题所暗示的那样:

bIsConnected = axCZKEM1.Connect_Net("192.168.0.77", Convert.ToInt32("4370"));
if (bIsConnected == true)
{
    iMachineNumber = 1;
    if (axCZKEM1.RegEvent(iMachineNumber, 65535))
    {
        this.axCZKEM1.OnFinger += new kemkeeper._IZKEMEvents_OnFingerEventHandler(axCZKEM1_OnFinger);
        this.axCZKEM1.OnVerify += new zkemkeeper._IZKEMEvents_OnVerifyEventHandler(axCZKEM1_OnVerify);
        // ...
    }
}

那将是一个完全不同的故事。如果是这种情况,请发表评论并且您仍对某些解决方案感兴趣。

答案 1 :(得分:1)

我有一种预感,使用串口的东西会尝试使用应用程序的事件循环来完成它的工作。所以它实际上绕过了整个调度程序和线程系统并阻止了应用程序。我在这个领域没有经验,所以我不知道如何解决它,但这是另一个问题。