4

作成されたのと同じスレッドでイベントを処理しようとするこのシナリオがあります。これは一般的に UiThread で行われますが、私は最初から UiThread を使用していません。基本的に次の手順でいくつかのテストがあります。私はいくつかの詳細を省略しました。これが私が思うように動作するかどうかはよくわかりません。

まず、現在のスレッドの Id を確認します

var myThreadId = Thread.CurrentThread.ManagedThreadId;

私は SynchronizationContext を作成し、設定は最新のものです

var _context = new SynchronizationContext();
SynchronizationContext.SetSynchronizationContext(_context);

次に、コンテキストに何らかのアクションを送信します (現在、別のスレッドにいます)

_context.Send(x => _action(sender, e), null);

このアクション内で、ThreadId を再度確認します

Assert.Equal(myThreadId, Thread.CurrentThread.ManagedThreadId);

これは失敗します。元のスレッドに戻ってはいけないのでしょうか?

4

2 に答える 2

12

新しい を作成するSynchronizationContextと、常にスレッド プールがラップされ、UI スレッドで実行されることはありませSendPost

MSDN から;

SynchronizationContext クラスは、同期のないフリースレッド コンテキストを提供する基本クラスです。

例えば;

void Button_Click(object sender, EventArgs e)
{
     var context = SynchronizationContext.Current;

     // this is executred on the UI thread.
     context.Send(() =>
     {
           // this is also executed on the UI thread.
     });

     Task.Run(() =>
     {
         // this is executed on a worker thread
         context.Send(() =>
         {
             // this is still executed on the UI thread!
         });
     }

     // what you are doing will always execute on a worker thread.
     var  myNewContext = new SynchronizationContext();
     SynchronizationContext.SetSynchronizationContext(myNewContext);

     myNewContext.Send(() =>
     {
         // this will run on a worker thread.
     }         
}

参考文献

並列コンピューティング - SynchronizationContext がすべて

于 2015-08-26T10:46:08.973 に答える
2

new を作成してorSynchronizationContextを使用することは、自分で行う場合と同様に、同期デリゲートの呼び出しとまったく同じです。コードはかなり単純です (ソースから取得):SendPost

public virtual void Send(SendOrPostCallback d, Object state)
{
    d(state);
}

DispatcherSynchronizationContextたとえば、WPF の UI メッセージ ループ スレッドを認識しているカスタム コンテキストの操作を模倣しようとしています。その振る舞いはここでは起こりません。

UI スレッドから来た場合は、コンテキストをキャプチャして渡す必要があります。

これは、クラスDispatcherSynchronizationContextを使用してどのキューが UI に対して機能するかで、より明確に確認できます。Dispatcher

/// <summary>
///     Synchronously invoke the callback in the SynchronizationContext.
/// </summary>
public override void Send(SendOrPostCallback d, Object state)
{
    // Call the Invoke overload that preserves the behavior of passing
    // exceptions to Dispatcher.UnhandledException.  
    if(BaseCompatibilityPreferences.GetInlineDispatcherSynchronizationContextSend() && 
       _dispatcher.CheckAccess())
    {
        // Same-thread, use send priority to avoid any reentrancy.
        _dispatcher.Invoke(DispatcherPriority.Send, d, state);
    }
    else
    {
        // Cross-thread, use the cached priority.
        _dispatcher.Invoke(_priority, d, state);
    }
}
于 2015-08-26T10:56:19.500 に答える