6

BeginInvoke がメイン スレッドから呼び出されるコードを継承しました (通常はパターンであるバックグラウンド スレッドではありません)。このシナリオで実際に何をするのかを理解しようとしています。

BeginInvoke で呼び出されているメソッドは、ウィンドウに表示されるメッセージの行に入りますか? ドキュメントによるとasynchronously、それが私の仮定です。

フレームワークは、BeginInvoke によって呼び出されたメソッドを開始するタイミングをどのように優先しますか?

編集: コードは次のようになります。

System.Action<bool> finalizeUI = delegate(bool open)
{
    try
    {
        // do somewhat time consuming stuff
    }
    finally
    {
        Cursor.Current = Cursors.Default;
    }
};

Cursor.Current = Cursors.WaitCursor;
BeginInvoke(finalizeUI, true);

これは Form_Load イベントで発生しています。

4

4 に答える 4

4

編集

コードを見ると、これが Form_Load から一部の初期化を移動する方法にすぎないことは明らかですが、ユーザーがフォームを操作する前に初期化が行われます。

への呼び出しBeginInvokeは Form_load 内にあり、別のオブジェクトでは呼び出されないため、これは Form.BeginInvoke への呼び出しです。では、何が起こっているのかというと、これです。

  1. Form_Load は Form.BeginInvoke にデリゲートを渡します。これにより、すべてのユーザー入力メッセージよりも前にあるフォームのメッセージ キューにメッセージが入れられます。カーソルを待機カーソルに設定します。
  2. Form_Load が返され、残りのフォーム初期化が完了すると、この時点でフォームが表示される可能性が高くなります。
  3. コードがメッセージ ポンプに落ちると、最初にキューにあるのがデリゲートであることがわかり、デリゲートが実行されます。
  4. デリゲートが完了すると、カーソルを通常のカーソルに戻し、戻ります
  5. 利益!

以下元記事


BeginInvoke を呼び出すオブジェクトに依存します。オブジェクトの派生元であるControl場合、 Control.BeginInvokeはコントロールを作成したスレッドで実行されます。JaredPar の回答を参照してください。

しかし、BeginInvoke の使用には別のパターンがあります。オブジェクトがデリゲートの場合、BeginInvoke は別のスレッドでコールバックを実行します。このスレッドは、その目的のために特別に作成することができます。

public class Foo
{
    ...
    public Object Bar(object arg)
    {
       // this function will run on a separate thread.
    }
}

...

// this delegate is used to Invoke Bar on Foo in separate thread, this must
// take the same arguments and return the same value as the Bar method of Foo
public delegate object FooBarCaller (object arg);

...

// call this on the main thread to invoke Foo.Bar on a background thread
//
public IAsyncResult BeginFooBar(AsyncCallback callback, object arg)
{
   Foo foo = new Foo();
   FooBarCaller caller = new FooBarCaller (foo.Bar);
   return caller.BeginInvoke (arg);
}

このパターンは、BeginInvoke がバックグラウンド スレッドではなくメイン スレッドから呼び出される理由の 1 つです。

于 2010-03-18T21:21:34.677 に答える
2

UI スレッドで BeginInvoke が呼び出された場合でも、メッセージが処理されるのを待つメッセージ キューに Windows メッセージを投稿するプロセスが実行されます。メッセージが処理されると、デリゲートが実行されます。このメッセージは、バックグラウンド スレッドから呼び出される場合とは異なり、優先順位が付けられることはありません。

于 2010-03-18T20:58:37.797 に答える
1

BackgroundWorker が広く使用される前は、UI スレッドで作成されたコントロール (ほとんどすべてのコントロール) で操作を行う前に、UI スレッドに同期する必要がありました。

「Windows フォーム コントロールへのスレッド セーフな呼び出し」セクションには、非常に優れた参考例があります。

于 2010-03-18T21:56:46.653 に答える
1

このシナリオでは、呼び出しが次のようになっていると思われます。

private void Button1_Click(object sender, ButtonClickEventArgs e)
{
    Control.BeginInvoke(new MethodInvoker(()=> /* code etc. */));
}

何が起こっているかというと、一部のコードはスレッドプール スレッドで実行され、コントロールを作成したスレッドでコントロールを更新しますが、Control.Invoke を使用すると、一部のコードはコントロールを作成したスレッドで実行され、コントロールを更新します。そのスレッドも。

于 2010-03-18T21:25:48.193 に答える