Holen Sie sich SynchronizationContext aus einem bestimmten Thread
Scheine ich nicht zu finden, wie man die SynchronizationContext
einer bestimmten Thread
:
Thread uiThread = UIConfiguration.UIThread;
SynchronizationContext context = uiThread.Huh?;
Warum sollte ich das brauchen?
Da muss ich post zu den UIThread von verschiedenen spots alle über die front-end-Anwendung. So definierte ich eine statische Eigenschaft in einer Klasse genannt UIConfiguration
. Ich habe diese Eigenschaft in der Program.Main
Methode:
UIConfiguration.UIThread = Thread.CurrentThread;
In diesem Augenblick kann ich sicher sein, ich habe das richtige thread ist, aber ich kann nicht eine statische Eigenschaft wie
UIConfiguration.SynchronizationContext = SynchronizationContext.Current
weil die WinForms-Implementierung der Klasse noch nicht installiert wurde. Da jeder thread hat seinen eigenen SynchronizationContext, muss es möglich sein, rufen Sie es aus einem bestimmten Thread
Objekt, oder bin ich völlig falsch?
- Zu einem späteren Zeitpunkt (nach der WinForms-Umsetzung geladen hat), kann man den UI-thread Synchronisation Kontext so: (ungetestet)
var context = (SynchronizationContext)someUiControl.Invoke(new Func<SynchronizationContext>(() => SynchronizationContext.Current));
und cache für die spätere Verwendung. - Sieht kreativ. Ich bräuchte eine Steuerung für das aber, was noch schlimmer ist, als brauchte Sie die SynchronizationContext-Objekt.
- Weiß nicht warum aber mein link zu dieser Frage von mir "Ist der Satz aus einem Buch ", wird Der aktuelle SynchronizationContext ist eine Eigenschaft des aktuellen Threads der" richtige"ist?" die nicht in Verwandte oder Verknüpfte Abschnitte auf der rechten Seitenleiste, so dass ich es in diesem Kommentar...also, hat er sich danach
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ist dies nicht möglich. Das problem ist, dass
SynchronizationContext
und einThread
sind wirklich zwei vollkommen verschiedene Konzepte.Während es wahr ist, dass die Windows Forms-und WPF-setup ein
SynchronizationContext
für den Haupt-thread, die meisten anderen threads nicht. Zum Beispiel, keiner der threads im ThreadPool enthalten Ihre eigenen SynchronizationContext (es sei denn, natürlich, Sie installieren Ihre eigenen).Es ist auch möglich, für eine
SynchronizationContext
werden völlig unabhängig von threads und threading. Eine Synchronisierung der Rahmen kann leicht eingerichtet werden, die synchronisiert auf einen externen Dienst oder einen gesamten thread-pool, etc.In deinem Fall, würde ich empfehlen die Einstellung Ihres
UIConfiguration.SynchronizationContext
innerhalb der ersten, Hauptformular Geladen Veranstaltung. Der Rahmen ist garantiert begann an diesem Punkt, und wird unbrauchbar, bis die Meldung Pumpe gestartet wurde, in jedem Fall.SynchronizationContext.Current
" geben Sie mir, wenn ich war, dass bestimmte thread? Für threads, die keinen Kontext hat, würde es wiedernull
nur als SynchronizationContext.Aktuelle tun würde.Load
event-handler.Ich weiß, das ist eine alte Frage, und sorry für den necro, aber ich habe gerade eine Lösung gefunden, um dieses problem, das ich dachte könnte nützlich sein, für diejenigen von uns, die schon googeln dieses (und es nicht erforderlich, dass eine Control-Instanz).
Grundsätzlich können Sie erstellen eine Instanz einer WindowsFormsSynchronizationContext und legen Sie den Kontext manuell in Ihr
Main
- Funktion, etwa so:Ich dies getan habe in meiner Anwendung, und es funktioniert perfekt, ohne Probleme. Jedoch, ich sollte darauf hinweisen, dass meine
Main
ist gekennzeichnet mit STAThread, so bin ich nicht sicher, ob diese noch funktionieren (oder ob es sogar notwendig), wenn IhrMain
ist gekennzeichnet mit MTAThread statt.EDIT: ich vergaß zu erwähnen es, aber
_UISyncContext
ist bereits definiert, in die Modul-Ebene in derProgram
Klasse in meiner Anwendung.Fand ich, wie die meisten prägnant und hilfreich, um mir die folgenden Passagen aus dem Buch von Alex Davies "Async in C# 5.0. O ' Reilly Verl., 2012", S..48-49:
"SynchronizationContext ist eine Klasse von der .NET Framework, welche die Möglichkeit hat, code ausführen, der in eine bestimmte Art von Faden.
Es gibt verschiedene Synchronisations-Kontexten verwendet .NET, von denen die wichtigsten sind der UI-thread-Kontexte verwendet, die von WinForms und WPF."
"Instanzen
SynchronizationContext
selbst nicht alles tun, sehr nützlich, so dass alle tatsächlichen Instanzen neigen dazu, werden Unterklassen.Es hat auch statische Elemente, aus denen Sie Lesen und die Kontrolle der Strom
SynchronizationContext
.Die aktuelle
SynchronizationContext
ist eine Eigenschaft des aktuellen Threads.Die Idee ist, dass an jedem Punkt, dass du immer in einem speziellen thread, Sie sollten in der Lage sein zu Holen Sie sich die aktuellen
SynchronizationContext
auf und speichern es. Später können Sie es verwenden, um code auszuführen, wieder auf die spezielle Faden, den Sie begonnen. All dies sollte möglich sein,, ohne genau zu wissen, welchen thread Sie begonnen, so lange wie Sie können, verwenden Sie die SynchronizationContext, Sie können Holen Sie sich zurück, um es.Die wichtige Methode der SynchronizationContext ist
Post
können, die eine Stellvertretung führen Sie in den richtigen Kontext zu".
"Einige SynchronizationContexts Kapseln einem einzigen thread, wie den UI-thread.
Einige Kapseln eine bestimmte Art von Faden — zum Beispiel die thread — pool- aber können wählen, eine von diesen threads zu posten der Stellvertretung. Einige nicht wirklich ändern, welcher thread der code läuft auf, sondern Sie sind nur zur überwachung eingesetzt, wie die ASP.NET Synchronisation Kontext"
Ich glaube nicht, dass jeder thread hat eigene
SynchronizationContext
- es muss nur eine thread-lokaleSynchronizationContext
.Warum nicht Sie stellen nur
UIConfiguration.UIThread
imLoaded
- event deiner form, oder etwas ähnliches?NullPointerException
.Komplette und funktionierende extension-methods für getting die
SynchronizationContext
aus einerThread
oderExecutionContext
(odernull
wenn keiner vorhanden ist), oder eineDispatcherSynchronizationContext
aus einerDispatcher
. Getestet auf .NET 4.6.2.Alle der oben genannten Funktionen am Ende aufrufen der
__get
code unten gezeigt, die garantiert einige Erklärungen.Beachten Sie, dass
__get
ist ein statisches Feld, pre-initialized mit einem entfernbare lambda-block. Dies ermöglicht es uns, ordentlich abfangen der erste Anrufer nur, um die einmalige Initialisierung, das bereitet einem winzigen und dauerhaften Ersatz delegieren, die viel schneller und Reflexion-kostenlos.Der Letzte Akt für die unerschrockenen Initialisierung Aufwand ist, tauschen Sie den Ersatz in "__get", die gleichzeitig und tragischerweise bedeutet, dass der code verwirft sich selbst, ohne Spuren zu hinterlassen, und alle nachfolgenden Anrufer gehen Sie direkt in die
DynamicMethod
richtigen, ohne auch nur einen Hauch von bypass-Logik.Das niedliche Teil ist ganz am Ende, wo--um tatsächlich abrufen des Werts für die vorbelegt ersten Anrufer--die Funktion angeblich nennt sich selbst mit seinem eigenen argument, sondern vermeidet recursing durch den Austausch selbst unmittelbar vor.
Es keinen besonderen Grund für den Nachweis dieser ungewöhnlichen Technik, die auf das spezielle problem der
SynchronizationContext
unter Diskussion auf dieser Seite. Greifen die_syncContext
Feld aus einerExecutionContext
leicht und trivial behandelt mit traditionellen Reflexion (plus einige Erweiterung Methode Zuckerguss). Aber ich dachte, ich Teile diesen Ansatz, die ich habe persönlich für eine Weile jetzt, denn es ist auch leicht angepasst und nur so weit anwendbar auf solche Fälle.Es ist besonders geeignet, wenn höchste Leistung erforderlich ist, den Zugriff auf den nicht-öffentlichen Bereich. Ich denke, dass ich ursprünglich verwendet, diese in einem QPC-basierte Frequenzzähler, wo das Feld war zu Lesen in einer engen Schleife, die Durchlaufen alle 20 oder 25 Nanosekunden, was nicht wirklich möglich sein, mit herkömmlichen Reflexion.
Damit ist die wichtigste Antwort, aber unten habe ich einige interessante Punkte, weniger relevant für den Fragesteller die Anfrage, außerdem ist die Technik nur demonstriert.
Laufzeit Anrufer
Für Klarheit, trennte ich die "installation swap" und "erste Verwendung" Schritte in zwei separate Zeilen im code oben gezeigt, im Gegensatz zu dem, was ich in meinem eigenen code (die folgende version vermeidet auch eine Haupt-Speicher Holen gegenüber der älteren, die potenziell einbezieht, für die thread-Sicherheit, siehe die detaillierte Diskussion unten):
In anderen Worten, alle Anrufer, einschließlich der ersten, Hole den Wert, der genau in der gleichen Weise, und keine Reflexion-code überhaupt benutzt wird, dies zu tun. Es schreibt nur der Ersatz getter. Mit freundlicher Genehmigung von il-visualizer, können wir sehen, die Körper der
DynamicMethod
im debugger zur Laufzeit:Lock-freien thread-Sicherheit
Sollte ich beachten Sie, dass die ein-und Auslagerung der Hauptteil der Funktion ist eine vollständig thread-sicheren Betrieb gegeben .NET Speicher Modell und die lock-free-Philosophie. Letzteres begünstigt vorwärts-Fortschritt gewährleistet mit den möglichen Kosten zu tun, doppelte oder überflüssige arbeiten. Multi-way-Race) um die Initialisierung ist korrekt, erlaubt eine vollständig fundierte theoretische Grundlage:
null
.IntPtr
, die garantiert atomar sind für alle jeweiligen Plattform Bitanzahl;GC
und somit kein Leck. In diese Art von Rennen, Verlierer sind alle Rennfahrer mit Ausnahme der letzten - finisher (da alle anderen Bemühungen bekommen munter und kurzerhand überschrieben mit identischem Ergebnis).Obwohl ich glaube, dass diese Punkte zu kombinieren, um vollständig schützen Sie den code unter jeden möglichen Umstand, wenn Sie immer noch misstrauisch oder vorsichtig von den insgesamt zu dem Ergebnis, können Sie immer fügen Sie eine zusätzliche Schicht von bulletproofing:
Es ist nur ein paraniod-version. Wie bei den früheren condensed one-liner, die .NET-Speicher-Modell garantiert, dass es genau einen store--und keine holt--Ort des '__get'. (Der vollständige erweiterte Beispiel ganz oben hat einen extra Arbeitsspeicher Holen, aber klingen immer noch durch den zweiten Punkt) Wie ich bereits erwähnte, keine dieser nötig sein sollte, für die Richtigkeit, aber es könnte in der Theorie, geben einen kleinen performance-bonus: durch abschließend endet das Rennen früher, die aggressive Spülen könnte, in einem extrem seltenen Fall verhindern, dass eine spätere Anrufer, auf eine dirty cache line von unnötig (aber wieder harmlos) racing.
Doppel-thunking
Anrufe in den letzten hyper-schnell-Methode sind noch thunked durch die statische Erweiterung Methoden wie oben gezeigt.
Denn wir müssen auch irgendwie darstellen entry point(s), die tatsächlich vorhanden sind zur compile-Zeit compiler binden vor und übertragen von Metadaten. Die Doppel-thunk ist ein kleiner Preis zu zahlen, für die überwältigende Bequemlichkeit stark typisierte Metadaten und intellisense in der IDE code angepasst, die können eigentlich nicht gelöst werden, erst zur Laufzeit. Doch es läuft mindestens so schnell wie eine statisch kompilierte code Weg schneller, dass dabei eine Reihe von Reflexion bei jedem Anruf, damit wir das beste aus beiden Welten!
SynchronizationContext
für dieThread
durch den Aufrufer angegeben, wenn es eine (und kritisch auf WPF, nicht lautlos verlangen, wenn es nicht funktioniert, das ist der eigentliche nutzen hier). Es stimmt, die Bedienung ist etwas nichts sagend ist, wenn der Anrufer gibtThread.CurrentThread
.SynchronizationContext
, aber nicht tatsächlich bekommen, eine für den thread angegeben für den Anrufer. Diesem Zusammenhang nicht berufen, auf den angegebenen thread, das ist, was Sie möchten, es zu tun, also es ist weniger als nutzlos.