Warum SynchronizationContext funktioniert nicht richtig?
Habe ich folgenden code:
[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);
}
Erwarte ich Letzte Methode, die ausgeführt werden, im ersten thread, d.h. der erste thread, in dem Synchronisierungskontext entnommen ist, denn ich nenne Post()
Methode in diesen Kontext. I. e. so etwas wie dieses:
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)
Ist es nicht der Sinn des SynchronizationContext? Aber eigentlich habe ich folgende Ausgabe:
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)
Was ist das problem? Macht das etwas schief gehen mit SynchronizationContext-oder habe ich etwas Missverständnis?
Update: ich nenne diese Methode als unit-test mit Resharper test-runner.
- Sie haben nicht uns gezeigt, wie diese aufgerufen werden, oder was mit der Synchronisation Kontext (z.B. einer WinForms-Ereignis-Schleife). Bitte aktualisieren Sie Ihre Frage mit einem kurzen, aber vollständigen Beispiel.
- Dies ist unit-test (MS-Test-Framework), ich benutze Resharper unit-test-runner.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sehen http://www.codeproject.com/KB/threads/SynchronizationContext.aspx
Es ist die Antwort, die Sie brauchen. Sie überschreiben muss
SynchronizationContext
machen es richtig, den Umgang mit Ihren-Operationen.Lesen ab:
SynchronizationContext
war Abstrakt, was würden Sie erstellen, zuweisenSynchronizationContext.Current
im unit-tests? Es ist besser als nichts.Default-Implementierung von SynchronizationContext nur ausführt, übergeben Delegierten in die aufrufende thread (in dem thread, ruft die Sende - /Post-Methode nicht der thread, fängt Kontext). Wenn Sie einige bestimmte Verhaltensweisen, wie die thread-Affinität für einige Operationen, die Sie durchführen sollten, diese manuell. BCL enthält einige out-of-box-Implementierungen für die Vereinfachung der Benutzeroberfläche Interoperabilität, wie WindowsFormsSynchronizationContext oder DispatcherSynchronizationContext.
Send
ruft den Delegaten auf den aufrufenden thread,Post
Warteschlangen an den thread-pool.Ihre Erwartung ist falsch, denn es gibt keinen Allgemeinen Weg zu "injizieren" ein Abgeordneter in einem Laufenden thread. Ihre "ersten thread" gestartet wurde in der test-runner, die ausgeführt wird, einen oder mehrere tests, und werden dann aufhören - es gibt keine Möglichkeit, Sie zu unterbrechen und sagen, es zu führen
CallbackInFirstThread
. DieSynchronizationContext
Klasse läuftPost
-ed-Delegierten in der thread-pool, denn das ist die einzige Möglichkeit, die es hat.Abgeleiteten Klassen wie
WindowsFormsSynchronizationContext
nutzen die message-loop in WinForms-Anwendungen zu übergeben, diePost
-ed-Delegat der UI-thread, aber es gibt keine Entsprechung in einem test-runner.Wenn Sie prüfen wollen, welche
SynchronizationContext
den code, den Sie testen wollen ist verwenden, können erstellen Sie Ihre eigene abgeleitete Klasse, setzt ein flag das können Sie in Ihrem test. Hier ist ein Beispiel:In
StartWorkInFirstThread
, den Kontext zu einer Instanz vonTestSynchronizationContext
:Nach Aufruf
BeginInvoke
, müssen Sie warten, bis diePost
geschehen, bevor Sie beenden den test, so rufen Sie:In
CallbackInFirstThread
können Sie überprüfen, welche Rahmen verwendet wird, mit etwas wie:Der Punkt ist, dass es keine einfache Möglichkeit, um tatsächlich post zurück zu dem ersten thread, aber Sie können überprüfen, dass die richtigen Kontext verwendet wird, so dass, wenn Ihr code ausgeführt wird, in einer realen Anwendung wird der callback ausgeführt werden, in dem UI-thread.