寻找自定义SynchronizationContext的示例(unit testing需要)

我需要一个自定义的SynchronizationContext :

  • 拥有一个运行“post”和“发送”代表的单个线程
  • 是按发送顺序发送的
  • 不需要其他方法

我需要这个,所以我可以单独测试一些线程代码,它们将在实际应用程序中与WinForm对话。

在我自己编写之前,我希望有人可以指出我的简单(和小)实现。

这个是我前一段时间写的,没有版权问题,也没有保证(系统没有投入生产):

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

idesign.net (在页面上搜索自定义同步上下文)有一个可以完成工作的SynchronizationContext,但是我需要它们更复杂。

有一个类似的要求 – unit testing服务器组件,以确认它的回调委托调用被编组到适当的SynchronizationContext并提出以下代码(基于Stephen Toub的博客文章http://blogs.msdn.com/b/pfxteam /archive/2012/01/20/10259049.aspx )我使用它自己的内部线程来处理Post() / Send()请求,而不是依赖于WPF / Winforms / ..执行调度。

  // 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(); } /// Dispatches an asynchronous message to the synchronization context. /// The System.Threading.SendOrPostCallback delegate to call. /// The object passed to the delegate. public override void Post(SendOrPostCallback d, object state) { if (d == null) throw new ArgumentNullException("d"); m_queue.Add(new KeyValuePair(d, state)); } ///  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); try { innerCallback.Item1(innerCallback.Item2); } finally { innerCallback.Item3.Set(); } } /// The queue of work items. private readonly BlockingCollection> m_queue = new BlockingCollection>(); private readonly Thread m_thread = null; /// Runs an loop to process all queued work items. private void ThreadWorkerDelegate(object obj) { SynchronizationContext.SetSynchronizationContext(obj as SynchronizationContext); try { foreach (var workItem in m_queue.GetConsumingEnumerable()) workItem.Key(workItem.Value); } catch (ObjectDisposedException) { } } } 

我已经调整了Bond的答案,以消除对WPF(Dispatcher)的依赖,并依赖于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); } } }