【问题标题】:Why is my GUI freezing?为什么我的 GUI 冻结?
【发布时间】:2014-08-22 21:49:49
【问题描述】:

我是 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

【问题讨论】:

  • 您是否尝试在没有工厂的情况下进行操作,例如。只是新的任务和开始?而且没有调度员。类似blog.yojimbocorp.com/2012/05/22/…
  • @Euphoric 是的,我做到了。事实上,我的原始代码没有工厂,也没有调度程序。我在绝望中补充道:)
  • 用 Thread.Sleep 替换 DoLoooongWork 时是否会发生冻结?
  • @Euphoric Man,你真是个天才!我用 Thread.Sleep(60) 替换,GUI 是免费的!我很高兴也很伤心...这是对 Interop DLL 的直接调用,它与串行端口等通信...如何冻结 GUI?
  • @ClickOk,也许如果你能展示一下DoLoooongWork 内部到底发生了什么,我们或许可以提供进一步的帮助。这是一个有点类似的问题,仅供参考:stackoverflow.com/q/21211998/1768303。是的,Dispatcher.BeginInvoke 在这里是多余的。

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


【解决方案1】:

我认为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.

[UPDATE]你在cmets中提到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);
        // ...
    }
}

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多