Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't we change apartment state of a ThreadPool thread and why don't we require a messagepump when ShowDialog is used?

Recently, I encountered this situation where I wanted to display a form on another thread (not the main/UI thread). I used a threadpool thread. The form hosted a RCW (for a COM component). Instantiating the form gave me an exception that the thread must be a STA. I tried to set the apartment state as STA. But, that didn't work either. I finally ended up creating a thread explicitly and that worked(I used ShowDialog and needn't create a meesage pump).

EDIT:

  • I know that threadpool threads are MTA. But, why can't it be set to STA? Just curious about this.

  • Another question that just popped in my head: Why don't we require a message pump when Showdialog() (to display a form) is used

like image 479
P.K Avatar asked Aug 15 '09 00:08

P.K


2 Answers

The apartment is selected by a call to CoInitializeEx(). A thread in the thread pool has already made that call, changing the apartment after that call is not possible.

That a thread pool would choose MTA makes sense, it is after all intended as a worker thread and shouldn't be blocked by method calls that need to be marshaled. Selecting a single-threaded apartment has the additional requirement of pumping a message loop. Something you'd never expect a threadpool thread to do.

The message loop is necessary because that's the vehicle that COM uses to marshal a call made on another thread. That call has to be "injected" in the STA thread, that's only possible if the thread is in a known quiescent state. If it isn't, such a call would cause major re-entrancy problems. Which it sometimes does even if the thread is pumping the loop.

You didn't need to pump a message loop yourself with Application.Run() because ShowDialog() starts its own message loop. That's how it gains modality. That nested loop exits as soon as the dialog closes.

like image 134
Hans Passant Avatar answered Oct 14 '22 17:10

Hans Passant


You shouldn't rely on specific behavior for thread pool threads. In general, a thread in the threadpool should be able to be replaced at any time by the CLR, without your knowledge. Thread pool threads are meant to be used with simple tasks, preferably short lived ones.

If you want to have fine grained control over thread settings, you should create a dedicated thread. Setting the apartment state is a perfect example of this.


In addition to the above, theoretical reasons, there's a practical problem with what you are attempting. Hosting a form on a second thread doesn't work (without a lot of extra work in place). Forms must be run on the same thread as the message pump - otherwise, they won't receive any windows messages, and will not update properly.

You can create a form on a separate thread if you implement a full message pump for that thread, but it's usually a better idea to just put your work items onto background threads, and use asyncrhonous programming techniques to keep your since UI thread responsive.

like image 37
Reed Copsey Avatar answered Oct 14 '22 15:10

Reed Copsey