2009-12-10 10 views
18

の例を探して、私はカスタムSynchronizationContext必要があります。カスタム(ユニットテストのために必要)のSynchronizationContext

  • は、「投稿」を実行し、送信してい
  • 代表を「送信」シングルスレッドを所有します彼らは他の方法が

を必要とされていない

  • に送信されているために、私はこのように私ができるユニットテスト、実際のアプリケーションでのWinFormする話をします、いくつかのスレッドのコードが必要です。

    私が自分で書く前に、誰かが私に簡単な(そして小さな)実装を教えてくれることを期待していました。

  • 答えて

    10

    、著作権で問題なく、無保証のいずれか(システムは、生産に行かなかった):

    using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Text; 
    using System.Threading; 
    using System.Windows.Threading; 
    
    namespace ManagedHelpers.Threads 
    { 
        public class STASynchronizationContext : SynchronizationContext, IDisposable 
        { 
         private readonly Dispatcher dispatcher; 
         private object dispObj; 
         private readonly Thread mainThread; 
    
         public STASynchronizationContext() 
         { 
          mainThread = new Thread(MainThread) { Name = "STASynchronizationContextMainThread", IsBackground = false }; 
          mainThread.SetApartmentState(ApartmentState.STA); 
          mainThread.Start(); 
    
          //wait to get the main thread's dispatcher 
          while (Thread.VolatileRead(ref dispObj) == null) 
           Thread.Yield(); 
    
          dispatcher = dispObj as Dispatcher; 
         } 
    
         public override void Post(SendOrPostCallback d, object state) 
         { 
          dispatcher.BeginInvoke(d, new object[] { state }); 
         } 
    
         public override void Send(SendOrPostCallback d, object state) 
         { 
          dispatcher.Invoke(d, new object[] { state }); 
         } 
    
         private void MainThread(object param) 
         { 
          Thread.VolatileWrite(ref dispObj, Dispatcher.CurrentDispatcher); 
          Console.WriteLine("Main Thread is setup ! Id = {0}", Thread.CurrentThread.ManagedThreadId); 
          Dispatcher.Run(); 
         } 
    
         public void Dispose() 
         { 
          if (!dispatcher.HasShutdownStarted && !dispatcher.HasShutdownFinished) 
           dispatcher.BeginInvokeShutdown(DispatcherPriority.Normal); 
    
          GC.SuppressFinalize(this); 
         } 
    
         ~STASynchronizationContext() 
         { 
          Dispose(); 
         } 
        } 
    } 
    
    +1

    これはかなり良く見え、素敵でシンプルです。それは本当に答えられ、約3年後に受け入れられたか?私はこれを試してみるつもりですが、 "それは機能しますか?" –

    +0

    @JonathonReinhart - はい、それは私の開発者テスト中に動作しました。問題が見つかった場合は、私が答えを向上させるためにお知らせください。 – Bond

    8

    idesign.net(ページのカスタム同期コンテキストの検索)には、ジョブを実行するSynchronizationContextがありますが、必要なものはもっと複雑です。この1つはいくつかの時間前に私が書いた

    +0

    このリンクは以後、腐敗しています。カスタム同期コンテキストを作成するための**適切な**コードの一部を含めることができますか? – IAbstract

    +0

    http://idesign.net/コードのダウンロードを参照してください。申し訳ありませんが、私はコピーの権利が私に答えに入れることができるかどうかわかりません。 –

    0

    私は削除するBondで答えを適応していますWPF(ディスパッチャ)への依存性、および代わりにWinFormsの依存:

    namespace ManagedHelpers.Threads 
        { 
        using System; 
        using System.Collections.Generic; 
        using System.Diagnostics; 
        using System.Linq; 
        using System.Text; 
        using System.Threading; 
        using System.Threading.Tasks; 
        using System.Windows.Forms; 
        using NUnit.Framework; 
    
        public class STASynchronizationContext : SynchronizationContext, IDisposable 
         { 
         private readonly Control control; 
         private readonly int mainThreadId; 
    
         public STASynchronizationContext() 
         { 
         this.control = new Control(); 
    
         this.control.CreateControl(); 
    
         this.mainThreadId = Thread.CurrentThread.ManagedThreadId; 
    
         if (Thread.CurrentThread.Name == null) 
          { 
          Thread.CurrentThread.Name = "AsynchronousTestRunner Main Thread"; 
          } 
         } 
    
         public override void Post(SendOrPostCallback d, object state) 
         { 
         control.BeginInvoke(d, new object[] { state }); 
         } 
    
         public override void Send(SendOrPostCallback d, object state) 
         { 
         control.Invoke(d, new object[] { state }); 
         } 
    
         public void Dispose() 
         { 
         Assert.AreEqual(this.mainThreadId, Thread.CurrentThread.ManagedThreadId); 
    
         this.Dispose(true); 
         GC.SuppressFinalize(this); 
         } 
    
         protected virtual void Dispose(bool disposing) 
         { 
         Assert.AreEqual(this.mainThreadId, Thread.CurrentThread.ManagedThreadId); 
    
         if (disposing) 
          { 
          if (control != null) 
           { 
           control.Dispose(); 
           } 
          } 
         } 
    
         ~STASynchronizationContext() 
         { 
         this.Dispose(false); 
         } 
         } 
        } 
    
    2

    は、同様の要件を持っていた - それは、コールバックデリゲートの呼び出しが適切なのSynchronizationContext上に整列化とfolloを思い付いたということを確認するために、サーバー・コンポーネントをテストユニットをウィジェットコード(Stephen Toubのブログ記事http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspxに基づいています)は、WPF/Winforms/..を使用してディスパッチを実行するのではなく、Post()/Send()リクエストを処理する独自の内部スレッドを使用するので、より簡単でより一般的です。

    // A simple SynchronizationContext that encapsulates it's own dedicated task queue and processing 
        // thread for servicing Send() & Post() calls. 
        // Based upon http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx but uses it's own thread 
        // rather than running on the thread that it's instanciated on 
        public sealed class DedicatedThreadSynchronisationContext : SynchronizationContext, IDisposable 
        { 
         public DedicatedThreadSynchronisationContext() 
         { 
          m_thread = new Thread(ThreadWorkerDelegate); 
          m_thread.Start(this); 
         } 
    
         public void Dispose() 
         { 
          m_queue.CompleteAdding(); 
         } 
    
         /// <summary>Dispatches an asynchronous message to the synchronization context.</summary> 
         /// <param name="d">The System.Threading.SendOrPostCallback delegate to call.</param> 
         /// <param name="state">The object passed to the delegate.</param> 
         public override void Post(SendOrPostCallback d, object state) 
         { 
          if (d == null) throw new ArgumentNullException("d"); 
          m_queue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state)); 
         } 
    
         /// <summary> As 
         public override void Send(SendOrPostCallback d, object state) 
         { 
          using (var handledEvent = new ManualResetEvent(false)) 
          { 
           Post(SendOrPostCallback_BlockingWrapper, Tuple.Create(d, state, handledEvent)); 
           handledEvent.WaitOne(); 
          } 
         } 
    
         public int WorkerThreadId { get { return m_thread.ManagedThreadId; } } 
         //========================================================================================= 
    
         private static void SendOrPostCallback_BlockingWrapper(object state) 
         { 
          var innerCallback = (state as Tuple<SendOrPostCallback, object, ManualResetEvent>); 
          try 
          { 
           innerCallback.Item1(innerCallback.Item2); 
          } 
          finally 
          { 
           innerCallback.Item3.Set(); 
          } 
         } 
    
         /// <summary>The queue of work items.</summary> 
         private readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> m_queue = 
          new BlockingCollection<KeyValuePair<SendOrPostCallback, object>>(); 
    
         private readonly Thread m_thread = null; 
    
         /// <summary>Runs an loop to process all queued work items.</summary> 
         private void ThreadWorkerDelegate(object obj) 
         { 
          SynchronizationContext.SetSynchronizationContext(obj as SynchronizationContext); 
    
          try 
          { 
           foreach (var workItem in m_queue.GetConsumingEnumerable()) 
            workItem.Key(workItem.Value); 
          } 
          catch (ObjectDisposedException) { } 
         } 
        } 
    
    関連する問題