我需要一個定製SynchronizationContext說:尋找一個自定義的SynchronizationContext的例子(用於單元測試)
- 旗下擁有運行一個單獨的線程「文章」和「發送」代表
- 是否發送在它們的順序依次在
- 發送需要
沒有其他的方法,我需要這個,所以我可以單元測試一些線程代碼,會說話的WinForm的實際應用。
在我寫自己的之前,我希望有人能指點我一個簡單的(和小的)實現。
我需要一個定製SynchronizationContext說:尋找一個自定義的SynchronizationContext的例子(用於單元測試)
沒有其他的方法,我需要這個,所以我可以單元測試一些線程代碼,會說話的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,可以完成這項工作,但它更復雜,我需要它們。
該鏈接已經腐爛並且通過。您是否可以包含一些**相關**代碼來創建自定義同步上下文? – IAbstract 2012-06-16 14:59:27
有關代碼,請參見http://idesign.net/Downloads,對不起,我不知道版權是否允許我將其置於答案中。 – 2012-06-18 13:44:41
我已經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);
}
}
}
也有類似的規定 - 單元測試服務器組件,以確認它的回調委託調用被整理到一個合適的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();
}
/// <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) { }
}
}
這看起來不錯,而且很好,很簡單。問了幾年後真的回答並接受了嗎?!我會試試這個,但是「它工作嗎?」 – 2012-06-20 22:46:15
@JonathonReinhart - 是的,它在我的開發測試期間確實有效,如果您發現任何問題,請讓我知道,以便我們改進答案。 – Bond 2012-06-21 07:06:09