views:

228

answers:

6

The Windows and Solaris thread APIs both allow a thread to be created in a "suspended" state. The thread only actually starts when it is later "resumed". I'm used to POSIX threads which don't have this concept, and I'm struggling to understand the motivation for it. Can anyone suggest why it would be useful to create a "suspended" thread?

Here's a simple illustrative example. WinAPI allows me to do this:

t = CreateThread(NULL,0,func,NULL,CREATE_SUSPENDED,NULL);
// A. Thread not running, so do... something here?
ResumeThread(t);
// B. Thread running, so do something else.

The (simpler) POSIX equivalent appears to be:

// A. Thread not running, so do... something here?
pthread_create(&t,NULL,func,NULL);
// B. Thread running, so do something else.

Does anyone have any real-world examples where they've been able to do something at point A (between CreateThread & ResumeThread) which would have been difficult on POSIX?

+15  A: 
  1. To preallocate resources and later start the thread almost immediately.
  2. You have a mechanism that reuses a thread (resumes it), but you don't have actually a thread to reuse and you must create one.
adf88
+1 those are very nice reasons for it.
alex tingle
Repeated multiple times it can be serious cost.
adf88
Also consider the system resources used by a thread - (virtual) memory, handles, context switching - all good reasons for thread pooling.
JBRWilkinson
+5  A: 

It can be useful to create a thread in a suspended state in many instances (I find) - you may wish to get the handle to the thread and set some of it's properties before allowing it to start using the resources you're setting up for it.

Starting is suspended is much safer than starting it and then suspending it - you have no idea how far it's got or what it's doing.

Another example might be for when you want to use a thread pool - you create the necessary threads up front, suspended, and then when a request comes in, pick one of the threads, set the thread information for the task, and then set it as schedulable.

I dare say there are ways around not having CREATE_SUSPENDED, but it certainly has its uses.

There are some example of uses in 'Windows via C/C++' (Richter/Nasarre) if you want lots of detail!

Ragster
A: 

I stumbled with a similar problem once upon I time. The reasons for suspended initial state are treated in other answer.

My solution with pthread was to use a mutex and cond_wait, but I don't know if it is a good solution and if can cover all the possible needs. I don't know, moreover, if the thread can be considered suspended (at the time, I considered "blocked" in the manual as a synonim, but likely it is not so)

ShinTakezou
+2  A: 

You might want to start a thread with some other (usually lower) priority or with a specific affinity mask. If you spawn it as usual it can run with undesired priority/affinity for some time. So you start it suspended, change the parameters you want, then resume the thread.

sharptooth
That suggests that you need it to get round deficiencies in the WinAPI. All those parameters to CreateThread() and you *still* can't create the thread you want! <shakes head>
alex tingle
+1  A: 

The threads we use are able to exchange messages, and we have arbitrarily configurable priority-inherited message queues (described in the config file) that connect those threads. Until every queue has been constructed and connected to every thread, we cannot allow the threads to execute, since they will start sending messages off to nowhere and expect responses. Until every thread was constructed, we cannot construct the queues since they need to attach to something. So, no thread can be allowed to do work until the very last one was configured. We use boost.threads, and the first thing they do is wait on a boost::barrier.

Cubbi
+1  A: 

There is an implicit race condition in CreateThread: you cannot obtain the thread ID until after the thread started running. It is entirely unpredictable when the call returns, for all you know the thread might have already completed. If the thread causes any interaction in the rest of that process that requires the TID then you've got a problem.

It is not an unsolvable problem if the API doesn't support starting the thread suspended, simply have the thread block on a mutex right away and release that mutex after the CreateThread call returns.

However, there's another use for CREATE_SUSPENDED in the Windows API that is very difficult to deal with if API support is lacking. The CreateProcess() call also accepts this flag, it suspends the startup thread of the process. The mechanism is identical, the process gets loaded and you'll get a PID but no code runs until you release the startup thread. That's very useful, I've used this feature to setup a process guard that detects process failure and creates a minidump. The CREATE_SUSPEND flag allowed me to detect and deal with initialization failures, normally very hard to troubleshoot.

Hans Passant
pthreads doesn't suffer from that race, since the thread ID is set by reference. pthread_create() can guarantee that the thread ID is set before the thread starts. The CreateThread() interface does have that problem, so I can see that it might need to be able to "start suspended".
alex tingle
Hmm, it is set by reference in CreateThread as well. Not sure what chicken is first.
Hans Passant