I can not find any documentation that specifies on which thread WebClient raises its events. I ran some tests and determined the following:
If called from a UI thread (say from an event handler) the event handler will be executed on that thread. As a test, I added an infinite loop after the call to OpenReadAsync. The event handler was never called.
If there is no UI thread, like in a console application, the event handler will be executed on a thread pool thread. In this case, if I wanted to provide some results the rest of the application, I would have to be aware of threading issues.
Is this behaviour documented anywhere? I found nothing.
I have the basically the same question concerning the new async features of C# - eventually, the asynchronous code will have to be executed. Will that also spawn a thread pool thread when there is no UI thread? Will that, in turn, require thread safe code?
I feel that I am missing something here - I can 开发者_开发百科only find very little information about this, but this seems important to me.
For WebClient
, I haven't found it documented either, but have seen the same behaviour as you. Essentially this can be described as "if there's an active synchronization context when the call is started, it's used - otherwise the thread pool is used."
For the async behaviour in C# 5, it depends on the implementation of whatever you're awaiting... but I believe the awaiter for Task<T>
will use TaskScheduler.Current
to schedule a continuation - which means you'll see the same sort of behaviour. (It's not necessarily just a UI thread which sets a task scheduler, but that's the most obvious example.)
When thread pool threads are used, it should still be thread-safe - the method is only executing in a single thread at a time, and I believe the Task Parallel Library performs all the required memory barriers.
If you're interested in how async hangs together behind the scenes, you might want to read my Eduasync blog series.
The WebClient Class implements the Event-based Asynchronous Pattern. The pattern is fully described in the Framework Design Guidelines, but MSDN also provides a few hints how it is implemented:
Implementors of the pattern use the AsyncOperationManager to create an AsyncOperation for each asynchronous operation and raise events using the AsyncOperation.Post Method. The Post Method executes the passed callback on the SynchronizationContext that was current at the time when the AsyncOperation was created.
The default SynchronizationContext in a WinForms or WPF application is the UI thread, or null
in a Console application. The WebClient Class apparently chooses to raise the events in a ThreadPool thread in the latter case, but this is an implementation detail.
精彩评论