【问题标题】:BeginInvoke is blocking the UI whereas Invoke is not.!BeginInvoke 会阻塞 UI,而 Invoke 不会。!
【发布时间】:2012-05-08 11:26:30
【问题描述】:

我对跨线程访问遇到的场景感到困惑。这是我想要做的:

主 UI 线程 - 菜单项单击我创建一个后台工作程序并异步运行它

private void actionSubMenuItem_Click(object sender, EventArgs e)
{
       ToolStripMenuItem itemSelected = (ToolStripMenuItem)sender;
       ExecuteTheActionSelected(itemSelected.Text);
}

方法ExecuteTheActionSelected如下:

private void ExecuteTheActionSelected(string actionSelected)
{
      BackgroundWorker localBackgroundWorker = new BackgroundWorker();
      localBackgroundWorker.DoWork += new DoWorkEventHandler(localBackgroundWorker_DoWork);
      localBackgroundWorker.RunWorkerAsync(SynchronizationContext.Current);
}

localBackgroundWorker_DoWork 有:

 ActionExecutionHelper actionExecutioner = new ActionExecutionHelper()
 actionExecutioner.Execute();

该类中的 Execute 方法具有方法调用程序,该方法调用程序实际上调用 UI 线程中的事件处理程序:

 public void Execute()
 {
      // ---- CODE -----
      new MethodInvoker(ReadStdOut).BeginInvoke(null, null);
 }

 protected virtual void ReadStdOut()
 {
      string str;
      while ((str = executionProcess.StandardOutput.ReadLine()) != null)
      {
          object sender = new object();
          DataReceivedEventArgs e = new DataReceivedEventArgs(str);
          outputDataReceived.Invoke(sender, e); 
          //This delegate invokes UI event handler
      }
 }

UI事件处理程序如下:

private void executionProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
    if (_dwExecuteAction != null)
    {
        _dwExecuteAction.ShowDataInExecutionWindow(e.Text);
    }
}

现在是跨线程问题

public void ShowDataInExecutionWindow(string message)
{
     if (rchtxtExecutionResults.InvokeRequired)
     {
            rchtxtExecutionResults.Invoke(new ShowDataExecutionDelegate(ShowDataInExecutionWindow), message);
     }
     else
     {
            this.rchtxtExecutionResults.AppendText(message + Environment.NewLine);
     }
}

此处Invoke 不会像 BeginInvoke 那样阻止 UI。 请帮助我理解这种情况,因为我很困惑。

【问题讨论】:

  • 恐怕我不知道答案,但我要找出答案的方法是查看多个级别的调用和后台工作人员如何相互作用,以及在哪里一切都实际执行,以便您了解一切如何组合在一起。

标签: c# winforms multithreading begininvoke invokerequired


【解决方案1】:

是的,这很正常。您从 Invoke() 中获得的好处是它阻塞 工作线程。当您使用 BeginInvoke() 时,线程会继续运行并以高于 UI 线程可以处理的速率发出调用请求。这取决于您要求 UI 线程做什么,但它开始成为每秒 1000 次调用左右的问题。

在这种情况下,UI 线程停止响应,它在泵送消息循环时不断地寻找另一个调用请求,并且不再执行其常规职责。不再处理输入和绘制请求。

问题的明确根源在于从流程中检索到的每一行输出的调用请求。它只是太快地生成它们。您需要通过降低调用速率来解决此问题。有一个简单的规则,你只是试图让一个人保持忙碌,每秒调用超过 25 次转动你产生的任何东西,但眼睛会模糊。因此,缓冲这些行并测量自上次调用以来经过的时间量。

还请注意,使用 Invoke() 是一种简单的解决方法,但不能完全保证它可以工作。这是一场竞态,工作线程可能总是比主线程重新进入消息循环并读取下一条消息早一点调用下一个 Invoke()。在这种情况下,您仍然会遇到完全相同的问题。

【讨论】:

  • 好的,解释一下 BeginInvoke() 阻塞 UI。但是为什么Invoke() 不会阻塞 UI 线程呢?当我使用Invoke() 时,我可以轻松访问其他控件
  • 因为它阻塞了工作线程,所以它不能如此频繁地用调用请求猛击 UI 线程。关键是 UI 线程实际上并没有被阻塞,它只是没有处理它的所有正常职责。
  • 还有一个问题!!这么小事怎么会知道?? :) 那个人需要对你所探索的内容有更多的深入了解。我搜索了很多网站,但从来没有得出这样的结论!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-23
  • 2020-12-01
  • 1970-01-01
  • 2021-08-29
  • 2016-05-31
  • 1970-01-01
相关资源
最近更新 更多