I seem not to find how to get the SynchronizationContext
of a given Thread
:
Thread uiThread = UIConfiguration.UIThread;
SynchronizationContext context = uiThread.Huh?;
Why should I need that?
Because I need to post to the UIThread from different spots all across the front end application. So I defined a static property in a class called UIConfiguration
. I set this property in the Program.Main
method:
UIConfiguration.UIThread = Thread.CurrentThread;
In that very moment I can be sure I have the right thread, however I cannot set a static property like
UIConfiguration.SynchronizationContext = SynchronizationContext.Current
because the WinForms implementation of that class has not yet been installed. Since each thread has it's own SynchronizationContext, it must be possible to retrieve it from a given Thread
object, or am I completely wrong?
I know this is an old question, and apologize for the necro, but I just found a solution to this problem that I figured might be useful for those of us who have been googling this (and it doesn't require a Control instance).
Basically, you can create an instance of a WindowsFormsSynchronizationContext and set the context manually in your
Main
function, like so:I have done this in my application, and it works perfectly without issues. However, I should point out that my
Main
is marked with STAThread, so I am not sure if this will still work (or if it's even necessary) if yourMain
is marked with MTAThread instead.EDIT: I forgot to mention it, but
_UISyncContext
is already defined at the module level in theProgram
class in my application.I don't believe that every thread does have its own
SynchronizationContext
- it just has a thread-localSynchronizationContext
.Why don't you just set
UIConfiguration.UIThread
in theLoaded
event of your form, or something similar?This is not possible. The problem is that a
SynchronizationContext
and aThread
are really two completely separate concepts.While it's true that Windows Forms and WPF both setup a
SynchronizationContext
for the main thread, most other threads do not. For example, none of the threads in the ThreadPool contain their own SynchronizationContext (unless, of course, you install your own).It's also possible for a
SynchronizationContext
to be completely unrelated to threads and threading. A synchronization context can easily be setup that synchronizes to an external service, or to an entire thread pool, etc.In your case, I'd recommend setting your
UIConfiguration.SynchronizationContext
within the initial, main form's Loaded event. The context is guaranteed to be started at that point, and will be unusable until the message pump has been started in any case.I found as the most concise and helpful to me the following passages from book by Alex Davies "Async in C# 5.0. O'Reilly Publ., 2012", p.48-49:
"SynchronizationContext is a class provided by the .NET Framework, which has the ability to run code in a particular type of thread.
There are various Synchronization Contexts used by .NET, the most important of which are the UI thread contexts used by WinForms and WPF."
"Instances of
SynchronizationContext
itself don’t do anything very useful, so all actual instances of it tend to be subclasses.It also has static members which let you read and control the current
SynchronizationContext
.The current
SynchronizationContext
is a property of the current thread.The idea is that at any point that you’re running in a special thread, you should be able to get the current
SynchronizationContext
and store it. Later, you can use it to run code back on the special thread you started on. All this should be possible without needing to know exactly which thread you started on, as long as you can use the SynchronizationContext, you can get back to it.The important method of SynchronizationContext is
Post
, which can make a delegate run in the right context".
"Some SynchronizationContexts encapsulate a single thread, like the UI thread.
Some encapsulate a particular kind of thread — for example, the thread pool — but can choose any of those threads to post the delegate to. Some don’t actually change which thread the code runs on, but are only used for monitoring, like the ASP.NET Synchronization Context"
Complete and working extension methods for getting the
SynchronizationContext
from aThread
orExecutionContext
(ornull
if none is present), or aDispatcherSynchronizationContext
from aDispatcher
. Tested on .NET 4.6.2.All of the above functions end up calling the
__get
code shown below, which warrants some explanation.Note that
__get
is a static field, pre-initialized with a discardable lambda block. This allows us to neatly intercept the first caller only, in order to run the one-time initialization, which prepares a tiny and permanent replacement delegate that's much faster and reflection-free.The final act for the intrepid initialization effort is to swap the replacement into '__get', which simultaneously and tragically means the code discards itself, leaving no trace, and all subsequent callers proceed directly into the
DynamicMethod
proper without even a hint of bypass logic.The cute part is the very end where--in order to actually fetch the value for the pre-empted first caller--the function ostensibly calls itself with its own argument, but avoids recursing by replacing itself immediately prior.
There's no particular reason for demonstrating this unusual technique on the particular problem of
SynchronizationContext
under discussion on this page. Grabbing the_syncContext
field out of anExecutionContext
could be easily and trivially addressed with traditional reflection (plus some extension method frosting). But I thought I'd share this approach which I've personally used for quite a while now, because it is also easily adapted and just as widely applicable to such cases.It's especially appropriate when extreme performance is necessary in accessing the non-public field. I think I originally used this in a QPC-based frequency counter where the field was read in a tight loop that iterated every 20 or 25 nanoseconds, which wouldn't really be possible with conventional reflection.
This concludes the main answer, but below I've included some interesting points, less relevant to the questioner's inquiry, moreso to the technique just demonstrated.
Runtime callers
For clarity, I separated the "installation swap" and "first usage" steps into two separate lines in the code shown above, as opposed to what I have in my own code (the following version also avoids one main-memory fetch versus the previous, potentially implicating thread-safety, see detailed discussion below):
In other words, all callers, including the first, fetch the value in exactly the same way, and no reflection code is ever used to do so. It only writes the replacement getter. Courtesy of il-visualizer, we can see the body of that
DynamicMethod
in the debugger at runtime:Lock-free thread safety
I should note that swapping in the function body is a fully thread-safe operation given the .NET memory model and the lock-free philosophy. The latter favors forward-progress guarantees at the possible expense of doing duplicate or redundant work. Multi-way racing to initialize is correctly permitted on a fully sound theoretical basis:
null
.IntPtr
, which is guaranteed to be atomic for any respective platform bitness;GC
and thus do no leak. In this type of race, losers are every racer except the last finisher (since everyone else's efforts get blithely and summarily overwritten with an identical result).Although I believe these points combine to fully protect the code as written under every possible circumstance, if you're still suspicious or wary of the overall conclusion, you can always add an extra layer of bulletproofing:
It's just a paraniod version. As with the earlier condensed one-liner, the .NET memory model guarantees that there is exactly one store--and zero fetches--to location of '__get'. (The full expanded example at the top does do an extra main memory fetch, but is still sound thanks to the second bullet point) As I mentioned, none of this should be necessary for correctness, but it could, in theory, give a miniscule performance bonus: by conclusively ending the race earlier, the aggressive flush could, in an extremely rare case, prevent a subsequent caller on a dirty cache line from unnecessarily (but again, harmlessly) racing.
Double-thunking
Calls into the final, hyper-fast method are still thunked through the static extension methods shown earlier. This is because we also need to somehow represent entry point(s) that actually exist at compile time for the compiler to bind against and propagate metadata for. The double-thunk is a small price to pay for the overwhelming convenience of strongly-typed metadata and intellisense in the IDE for customized code that can't actually be resolved until runtime. Yet it runs at least as fast as statically compiled code, way faster that doing a bunch of reflection on every call, so we get the best of both worlds!