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();

ExecuteUIスレッドでイベントハンドラーを実際に呼び出すメソッドインボーカーを持つそのクラスのメソッド:

 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 に答える