Does the stack reserved/commited for a thread get freed when
the thread terminates
the thread object is destroyed
(i.e. the thread is terminated and all handles to the thread are closed)
?
More broadly, are there significant resources associated with a thread that has terminated, but still exists since there are valid handles to it?
Reason: I need to modify a kind of "scoped singleton", so it doesn't return a single object, but a per-thread object. I cannot rely on thread creation/termination notices, much less on process-wide ones.
At the moment, I store the objects in a map<ThreadID, Object>, with a cache cleanup policy that's suitable for my application. To protect myself from the OS "recycling" thread ID's, I keep an handle to the thread open. (Rec
A side effect would be holding open handles to long-terminated threads in some corner cases.
According to "Windows VIA C/C++" by Richter and Nasarre (A must-have book for any C++ Windwos programmer) p.154:
Terminating a Thread
A thread can be terminated in four
ways:
The thread function returns. (This is highly recommended.)
The thread kills itself by calling the ExitThread function. (Avoid this
method.)
A thread in the same process or in another one calls the TerminateThread
function. (Avoid this method.)
The process containing the thread terminates. (Avoid this method.)
The Thread Function Returns
You should always design your thread
functions so that they return when you
want the thread to terminate. This is
the only way to guarantee that all
your thread's resources are cleaned up
properly.
Having your thread function return
ensures the following:
All C++ objects created in your thread function will be destroyed
properly via their destructors.
The operating system will properly free the memory used by the thread's
stack.
The system will set the thread's exit code (maintained in the thread's
kernel object) to your thread
function's return value.
The system will decrement the usage count of the thread's kernel object.
The ExitThread Function
You can force your thread to terminate by having it call ExitThread:
VOID ExitThread(DWORD dwExitCode);
This function terminates the thread
and causes the operating system to
clean up all the operating system
resources that were used by the
thread. However, your C/C++ resources
(such as C++ class objects) will not
be destroyed. For this reason, it is
much better to simply return from your
thread function instead of calling
ExitThread yourself.
Of course, you use ExitThread's
dwExitCode parameter to tell the
system what to set the thread's exit
code to. The ExitThread function does
not return a value because the thread
has terminated and cannot execute any
more code.
Note The recommended way to have a
thread terminate is by having its
thread function simply return (as
described in the previous section).
However, if you use the method
described in this section, be aware
that the ExitThread function is the
Windows function that kills a thread.
If you are writing C/C++ code, you
should never call ExitThread. Instead,
you should use the C++ run-time
library function _endthreadex. If you
do not use Microsoft's C++ compiler,
your compiler vendor will have its own
alternative to ExitThread. Whatever
this alternative is, you must use it.
The TerminateThread Function
A call to
TerminateThread also kills a thread:
BOOL TerminateThread( HANDLE
hThread, DWORD dwExitCode);
Unlike ExitThread, which always kills
the calling thread, TerminateThread
can kill any thread. The hThread
parameter identifies the handle of the
thread to be terminated. When the
thread terminates, its exit code
becomes the value you passed as the
dwExitCode parameter. Also, the
thread's kernel object has its usage
count decremented.
Note The TerminateThread function is
asynchronous. That is, it tells the
system that you want the thread to
terminate but the thread is not
guaranteed to be killed by the time
the function returns. If you need to
know for sure that the thread has
terminated, you might want to call
WaitForSingleObject or a similar function,
passing the handle of the thread.
A well-designed application never uses
this function because the thread being
terminated receives no notification
that it is dying. The thread cannot
clean up properly, and it cannot
prevent itself from being killed.
Note When a thread dies by returning
or calling ExitThread, the stack for
the thread is destroyed. However, if
TerminateThread is used, the system
does not destroy the thread's stack
until the process that owned the
thread terminates. Microsoft purposely
implemented TerminateThread in this
way. If other still-executing threads
were to reference values on the
forcibly killed thread's stack, these
other threads would raise access
violations. By leaving the killed
thread's stack in memory, other
threads can continue to execute just
fine.
In addition, dynamic-link libraries
(DLLs) usually receive notifications
when a thread is terminating. If a
thread is forcibly killed with
TerminateThread, however, the DLLs do
not receive this notification, which
can prevent proper cleanup.
When a Thread Terminates
The following actions occur when a
thread terminates:
All User object handles owned by the
thread are freed. In Windows, most
objects are owned by the process
containing the thread that creates the
objects. However, a thread owns two
User objects: windows and hooks. When
a thread dies, the system
automatically destroys any windows and
uninstalls any hooks that were created
or installed by the thread. Other
objects are destroyed only when the
owning process terminates.
The thread's exit code changes from
STILL_ACTIVE to the code passed to
ExitThread or TerminateThread.
The state of the thread kernel object
becomes signaled.
If the thread is the last active
thread in the process, the system
considers the process terminated as
well.
The thread kernel object's usage count
is decremented by 1.
When a thread terminates, its
associated thread kernel object
doesn't automatically become freed
until all the outstanding references
to the object are closed.
Once a thread is no longer running,
there isn't much any other thread in
the system can do with the thread's
handle. However, these other threads
can call GetExitCodeThread to check
whether the thread identified by
hThread has terminated and, if it has,
determine its exit code:
BOOL GetExitCodeThread( HANDLE
hThread, PDWORD pdwExitCode);
The exit code value is returned in the
DWORD pointed to by pdwExitCode. If
the thread hasn't terminated when
GetExitCodeThread is called, the
function fills the DWORD with the
STILL_ACTIVE identifier (defined as
0x103). If the function is successful,
TRUE is returned.
Maybe you should use pthread_getspecific, pthread_setspecific and pthread_key_create to manage your per thread singleton.
Related
Is the thread in MS Windows with C++ a time slice or the execution of a function or both?
A thread is executing a function which is a block of code inside an outer loop. If you send a signal (via a global variable) to break from the outer loop. The function returns, but what happens to the running thread assuming it is a time slice of execution?
Neither.
If your scheduler is set to a time-slice algorithm then the time-slice represents when and how long your thread will run.
A thread is an object that manages a block of executable code that can be scheduled. Typically, as part of thread creation you pass a function pointer to that block of code. When the "job" of the executable code is done the thread is destroyed.
In 32-bit and 64-bit Windows, every thread runs a specified function. Conceptually speaking, the initial thread of a new process runs the application's main function, and every additional thread runs a function specified by the programmer when the thread is created. See the documentation for CreateThread; the lpStartAddress argument specifies the function for the thread to run.
(In fact, each thread also runs operating system code, and usually runtime library code as well, but that's an implementation detail that doesn't matter for our purposes.)
Conceptually, when any particular thread is running on a particular CPU core, it might stop for either of two reasons: because the thread has stopped running altogether, or because of a context switch. In the case of a context switch, the thread will be started up again at a later time, and from the thread's point of view everything will look the same as it did when it was interrupted.
(In fact, the OS may also interrupt the thread in order to run device driver or other operating system code. This doesn't involve a context switch; the device driver code runs in the context of the interrupted thread, which is one of the reasons device drivers are hard to write.)
Here are some of the reasons the thread might stop running altogether ["exit"]:
The function the thread was created to run has exited.
The thread calls ExitThread().
Some other thread calls TerminateThread().
Here are some of the reasons there might be a context switch:
The thread's timeslice has expired.
Another thread with a higher priority has become ready to run.
The thread calls Sleep() or one of the wait functions.
It's hard to tell what you're trying to ask, so this may not have addressed it. But perhaps it will clarify things enough to allow you to ask your question in words I can understand.
I have hand-made thread pool. Threads read from completion port and do some other stuff. One particular thread has to be ended. How to interrupt it's waiting if it hangs on GetQueuedCompletionStatus() or GetQueuedCompletionStatusEx()?
Finite timeout (100-1000 ms) and exiting variable are far from elegant, cause delays and left as last resort.
CancelIo(completionPortHandle) within APC in target thread causes ERROR_INVALID_HANDLE.
CancelSynchronousIo(completionPortHandle) causes ERROR_NOT_FOUND.
PostQueuedCompletionStatus() with termination packet doesn't allow to choose thread.
Rough TerminateThread() with mutex should work. (I haven't tested it.) But is it ideologically good?
I tried to wait on special event and completion port. WaitForMultipleObjects() returned immediately as if completion port was signalled. GetQueuedCompletionStatus() shows didn't return anything.
I read Overlapped I/O: How to wake a thread on a completion port event or a normal event? and googled a lot.
Probably, the problem itself – ending thread's work – is sign of bad design and all my threads should be equal and compounded into normal thread pool. In this case, PostQueuedCompletionStatus() approach should work. (Although I have doubts that this approach is beautiful and laconic especially if threads use GetQueuedCompletionStatusEx() to get multiple packets at once.)
If you just want to reduce the size of the thread pool it doesn't matter which thread exits.
However if for some reason you need to signal to an particular thread that it needs to exit, rather than allowing any thread to exit, you can use this method.
If you use GetQueuedCompletionStatusEx you can do an alertable wait, by passing TRUE for fAlertable. You can then use QueueUserAPC to queue an APC to the thread you want to quit.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms684954(v=vs.85).aspx
If the thread is busy then you will still have to wait for the current work item to be completed.
Certainly don't call TerminateThread.
Unfortunately, I/O completion port handles are always in a signaled state and as such cannot really be used in WaitFor* functions.
GetQueuedCompletionStatus[Ex] is the only way to block on the completion port. With an empty queue, the function will return only if the thread becomes alerted. As mentioned by #Ben, the QueueUserAPC will make the the thread alerted and cause GetQueuedCompletionStatus to return.
However, QueueUserAPC allocates memory and thus can fail in low-memory conditions or when memory quotas are in effect. The same holds for PostQueuedCompletionStatus. As such, using any of these functions on an exit path is not a good idea.
Unfortunately, the only robust way seems to be calling the undocumented NtAlertThread exported by ntdll.dll.
extern "C" NTSTATUS __stdcall NtAlertThread(HANDLE hThread);
Link with ntdll.lib. This function will put the target thread into an alerted state without queuing anything.
Can a Windows thread suspend itself with SuspendThread()?
I can awake it from another one but, can it call SuspendThread(GetCurrentThreadId())?
It seems this is possible, but with a slight alteration (see the cygwin mailing list discussing this here):
SuspendThread(GetCurrentThread());
I also found MSDN saying a thread should only suspend itself, but it doesn't make it clear for me. I quote (from here, emphasis mine):
This function is primarily designed for use by debuggers. It is not intended to be used for thread synchronization. Calling SuspendThread on a thread that owns a synchronization object, such as a mutex or critical section, can lead to a deadlock if the calling thread tries to obtain a synchronization object owned by a suspended thread. To avoid this situation, a thread within an application that is not a debugger should signal the other thread to suspend itself. The target thread must be designed to watch for this signal and respond appropriately.
Yes, you can use SuspendThread on current thread. Good read on the topic.
As a method of creating reusable threads for work tasks without the overhead of create and terminate tasks, suspend and resume thread could be used to quiesce a thread at the end of the task. When work is dispatch to the thread, resume it.
may be I misunderstood something but...
When I call pthread_mutex_lock() and then call pthread_mutex_lock() out of the same thread again without calling pthread_mutex_unlock(), the second call of pthread_mutex_lock() will block.
But: when I call EnterCriticalSection() and call EnterCriticalSection() out of the same thread again without calling LeaveCriticalSection(), the second call of EnterCriticalSection() will NOT block since it is called out of the same thread (what is a very weird behaviour for me).
So my question is there a WinAPI function available that behaves like pthread_mutex_lock() and locks independent from the thread context?
I'm aware of libpthread for Windows but I prefer to have a WinAPI function here.
You could use a Semaphore with the maximum count set to one.
See Semaphore Objects
When you successfully acquire the semaphore, its count is decremented: going to zero in our case.
No other thread can acquire it, including the current one.
pthread_mutex_lock documentation:
If the mutex type is PTHREAD_MUTEX_RECURSIVE, then the mutex maintains the concept of a lock count. When a thread successfully acquires a mutex for the first time, the lock count is set to one. Every time a thread relocks this mutex, the lock count is incremented by one. Each time the thread unlocks the mutex, the lock count is decremented by one. When the lock count reaches zero, the mutex becomes available for other threads to acquire. If a thread attempts to unlock a mutex that it has not locked or a mutex which is unlocked, an error will be returned.
MSDN ReleaseMutex states:
A thread can specify a mutex that it already owns in a call to one of the wait functions without blocking its execution. This prevents a thread from deadlocking itself while waiting for a mutex that it already owns. However, to release its ownership, the thread must call ReleaseMutex one time for each time that it obtained ownership (either through CreateMutex or a wait function).
The wait functions are the equivalent to pthread_mutex_lock.
See Mutex Objects (Windows) to get more details about this API.
And this stackoverflow entry to see what the CRITICAL_SECTION object contains. This will disclose
that the CRITICAL_SECTION object holds - among others - a value LockCount to allow recursive use. See the EnterCriticalSection function to learn about this feature.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms686289%28v=vs.85%29.aspx
According to msdn, in the remarks sections, it states:
"If the thread that set the timer terminates and there is an associated completion routine, the timer is canceled. However, the state of the timer remains unchanged. If there is no completion routine, then terminating the thread has no effect on the timer."
Then further down, it states:
"If the thread that called SetWaitableTimer exits, the timer is canceled. This stops the timer before it can be set to the signaled state and cancels outstanding APCs; it does not change the signaled state of the timer."
Hence my question,
if I have one thread calling SetWaitableTimer without an associated completion routine and another thread calling WaitOnMultipleObjects(passing in the timer object handle) and the thread that calls SetWaitiableTmer exits shortly thereafter, would the timer object be cancelled or would it still become signaled when the period expires?
To give more information directly from the implementation of waitable timers: if you use a CompletionRoutine, the timer is placed on a linked list chained off the thread which called SetWaitableTimer. When the thread is terminated, the kernel walks the dying thread's linked list and cancels are timers which are still queued.
If you're not using a completion routine, the timer is never added to any thread's linked list and thus isn't cancelled when any particular thread dies.
The documentation is somewhat unclear. I think the best you can do is test it yourself. I believe however that the timer cancels automatically only if the I/O completion routine is used.
I can give some "theoretical" background about windows APCs, to justify my (educated) guess.
APC = "asynchronous procedure call". In windows every user-mode thread is equipped with a so-called APC queue, a system-managed queue of procedures that must be called on this thread. A thread may enter a so-called "alertable wait" state (on purpose), during which it may execute one or more of the procedures in this queue. You may either put the procedure call in the APC queue manually, or issue an I/O, which on completion will "put" the procedure call there.
In simple words the scenario is the following: you issue several I/Os, and then you wait for either of them to complete (or fail), and, perhaps, some other events. You then call one of the alertable-waiting functions: SleepEx, WaitForMultipleObjectsEx or similar.
Important note: this mechanism is designed to support a single-threaded concurrency. That is, the same thread issues several I/Os, waits for something to happen, and responds appropriately. All the APC routines are guaranteed to be called in the same thread. Hence - if this thread exits - there's no way to call them. Hence - all the outstanding I/Os are also cancelled.
There are several Windows API functions that deal with asynchronous I/O, whereas they allow a choice of several completion mechanisms (such as ReadFileEx): APC, setting an event, or putting a completion in the I/O completion port. If those functions are used with APC - they automatically cancel the I/O if the issuing thread exits.
Hence, I guess that waitable timer auto-cancels only if used with APC.