我有以下代码:
[TestMethod]
public void StartWorkInFirstThread()
{
if (SynchronizationContext.Current == null)
SynchronizationContext.SetSynchronizationContext(
new SynchronizationContext());
var syncContext = SynchronizationContext.Current;
Console.WriteLine("Start work in the first thread ({0})",
Thread.CurrentThread.ManagedThreadId);
var action = ((Action) DoSomethingInSecondThread);
action.BeginInvoke(CallbackInSecondThread, syncContext);
// Continue its own work
}
private static void DoSomethingInSecondThread()
{
Console.WriteLine("Do something in the second thread ({0})",
Thread.CurrentThread.ManagedThreadId);
}
private void CallbackInSecondThread(IAsyncResult ar)
{
Console.WriteLine("Callback in the second thread ({0})",
Thread.CurrentThread.ManagedThreadId);
var syncContext = (SynchronizationContext) ar.AsyncState;
syncContext.Post(CallbackInFirstThread, null);
}
private void CallbackInFirstThread(object obj)
{
Console.WriteLine("Callback in the first thread ({0})",
Thread.CurrentThread.ManagedThreadId);
}我期望在第一个线程中执行最后一个方法,即从其中提取SynchronizationContext的初始线程,因为我调用了这个上下文的Post()方法。也就是这样的东西:
Start work in the first thread (28)
Do something in the second thread (17)
Callback in the second thread (17)
Callback in the first thread (28)这不是SynchronizationContext的意思吗?但实际上,我有以下输出:
Start work in the first thread (28)
Do something in the second thread (17)
Callback in the second thread (17)
Callback in the first thread (7),问题是什么?SynchronizationContext出什么问题了还是我有什么误会?
更新:--我使用Resharper将此方法称为单元测试。
发布于 2010-10-08 17:05:49
请参阅http://www.codeproject.com/KB/threads/SynchronizationContext.aspx
这是你需要的答案。您必须重写SynchronizationContext以使其正确处理您的操作。
从以下开始阅读:
请注意,DoWork是在线程11上执行的,该线程与Run1相同。没有太多的SynchronizationContext进入主线程。为什么?怎么回事?好吧..。这是当你意识到生活中没有任何东西是免费的时候。线程不能只是在它们之间切换上下文,它们必须有一个内置的基础设施才能做到这一点。例如,UI线程使用消息泵,在它的SynchronizationContext中,它利用消息泵来同步到UI线程。
发布于 2010-10-08 17:01:32
SynchronizationContext的默认实现只是在调用线程中执行传递的委托(在调用发送/Post方法的线程中,而不是捕获上下文的线程中)。如果您需要一些特定的行为,比如某些操作的线程关联,您应该手动实现这一点。BCL包含很少的开箱即用的实现来简化UI互操作性,比如WindowsFormsSynchronizationContext或DispatcherSynchronizationContext.
发布于 2013-01-03 17:32:43
您的期望是错误的,因为没有将委托“注入”到正在运行的线程的一般方法。您的“第一个线程”在测试运行程序中启动,将执行一个或多个测试,然后停止--无法中断它并让它运行CallbackInFirstThread。SynchronizationContext类在线程池中运行Post-ed委托,因为这是它唯一的选项。
像WindowsFormsSynchronizationContext这样的派生类利用WinForms应用程序中的消息循环将Post-ed委托传递给UI线程,但是在测试运行程序中没有等效的。
如果要检查正在测试的代码使用的是哪个SynchronizationContext,可以创建自己的派生类,该类设置可以在测试中签入的标志。下面是一个例子:
public class TestSynchronizationContext : SynchronizationContext
{
[ThreadStatic]
private static object _CurrentPostToken;
/// <summary>
/// Gets the context's token, if the current thread is executing a delegate that
/// was posted to this context; otherwise, null.
/// </summary>
public static object CurrentPostToken
{
get
{
return _CurrentPostToken;
}
}
public object Token { get; private set; }
/// <summary>
/// Gets a WaitHandle that is set after the context executes a posted delegate.
/// </summary>
public AutoResetEvent PostHandle { get; private set; }
public TestSynchronizationContext(object token)
{
Token = token;
PostHandle = new AutoResetEvent(false);
}
public override void Post(SendOrPostCallback d, object state)
{
try
{
_CurrentPostToken = Token;
// Execute the callback on this thread, so that we can reset the context
// when it's finished.
d(state);
}
finally
{
_CurrentPostToken = null;
}
// The test method will wait on this handle so that it doesn't exit before
// the synchronization context is called.
PostHandle.Set();
}
}在StartWorkInFirstThread中,将上下文设置为TestSynchronizationContext实例
SynchronizationContext.SetSynchronizationContext(
new TestSynchronizationContext(new object()));调用BeginInvoke之后,需要等待Post在退出测试之前发生,因此调用:
((TestSynchronizationContext)SynchronizationContext.Current).PostHandle.WaitOne(1000);在CallbackInFirstThread中,您可以检查以下内容所使用的上下文:
Assert.IsNotNull(TestSynchronizationContext.CurrentPostToken);要点是,实际上回发到第一个线程并不是一种简单的方法,但您可以检查是否使用了正确的上下文,以便当您的代码在实际应用程序中运行时,回调将在UI线程中运行。
https://stackoverflow.com/questions/3892453
复制相似问题