6

我对跨线程访问遇到的场景感到困惑。这是我正在尝试做的事情:

主 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 不会阻塞 UI,因为 BeginInvoke 会阻塞。请帮助我理解这种情况,因为我很困惑。

4

1 回答 1

7

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

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

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

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

于 2012-05-08T12:22:20.933 回答