How do I terminate a thread in C and C++

  • 2020-04-02 01:05:29
  • OfStack

To terminate a thread, use the following method:
1. The thread function returns (this method is best used).
2. By calling the ExitThread function, the thread will undo itself (preferably without using this method).
3. A thread in the same process or another process calls the TerminateThread function (this method should be avoided).
ExitProcess and TerminateProcess functions can also be used to terminate a thread (this method should be avoided).

Here's how to terminate a thread run: 1-4, and what happens when a thread terminates: 5.

1. Return of thread function
Threads should always be designed to return when they want to terminate. This is the only way to ensure that all thread resources are cleared correctly.
If the thread can return, the following can be ensured:
(1) all C++ objects created in the thread function will be properly undone by their undo function.
(2) the operating system will correctly free up the memory used by the thread stack.
(3) the system sets the exit code of the thread (maintained in the kernel object of the thread) to the return value of the thread function.
(4) the system will decrement the usage count of the thread kernel object.

2. ExitThread
You can have a thread call the ExitThread function to force the thread to terminate:
Function prototype:
VOID ExitThread (DWORD dwExitCode);
This function terminates the thread and causes the operating system to clear all operating system resources used by the thread. However, C++ resources (such as C++ class objects) will not be undone. For this reason, it is better to return from a thread function than by calling ExitThread.
Of course, you can use ExitThread's dwExitThread parameter to tell the system what to set the exit code for the thread. The ExitThread function does not return any value because the thread has terminated and cannot execute any more code.
Note that the best way to terminate a thread is to have its thread function return. However, if you use the methods described in this section, you should know that the ExitThread function is a function that Windows USES to undo threads. If you write C/C++ code, you should never call ExitThread. The Visual C++ runtime library function _endthreadex should be used. If you don't use Microsoft's Visual C++ compiler, your compiler vendor has its own alternative function for ExitThread. Whatever the substitution function is, it must be used.

TerminateThread function
Calling the TerminateThread function also terminates a thread:
Function prototype:


BOOL TerminateThread( 
HANDLE hThread, 
DWORD dwExitCode);
 
Unlike exitthreads, which always undo the calling thread, TerminateThread can undo any thread. The hThread parameter is used to identify a handle to the thread being terminated. When a thread terminates, its exit code becomes the value you pass as a dwExitCode parameter. At the same time, the usage count of the thread's kernel object is also decremented.
Note that the TerminateThread function runs asynchronously That is, it tells the system that you want the thread to terminate, but there is no guarantee that the thread will be undone when the function returns. If you need to know for sure that the thread has terminated, you must call WaitForSingleObject or a similar function, passing the handle to the thread.
A well-designed application never USES this function because the terminated thread does not receive notification that it has been revoked. The thread cannot be cleared correctly and cannot prevent itself from being undone.
Note that when a thread is undone using methods that return or call ExitThread, the thread's memory stack is undone as well. However, if you use TerminateThread, the system does not undo the stack of a thread until the process that owns it terminates. Microsoft intentionally USES this method to implement TerminateThread. If other threads that are still executing reference values on the stack of threads that have been forced to undo, access violations can occur for other threads. If the stack of the canceled thread is left in memory, the other threads can continue to run well.
In addition, the DLL usually receives notifications when a thread terminates. If TerminateThread is used to force a thread to terminate, the DLL does not receive notification, which prevents proper cleanup.

Undo the thread when the process terminates
The ExitProcess and TerminateProcess functions can also be used to terminate a thread. The difference is that these threads will cause all threads in the terminated process to terminate. In addition, since the entire process has been shut down, all resources used by the process must have been cleared. This, of course, includes the stack for all threads. These two functions cause the remaining threads in the process to be forcibly undone, just as TerminateThread is called from each remaining thread. Obviously, this means that the correct application cleanup did not occur, that is, the C++ object undo function was not called, the data was not transferred to disk, and so on.

5. The operation that occurs when the thread terminates the run
When the thread terminates, the following operations occur:
(1) all user objects owned by the thread are released. In Windows, most objects are owned by processes that contain the thread that created them. But a thread has two user objects, a window and a hook. When a thread terminates, the system automatically revokes any Windows and unloads any hooks created or installed by the thread. Other objects are undone only when a process with a thread terminates.
(2) the exit code of the thread is changed from STILL_ACTIVE to the code passed to ExitThread or TerminateThread.
(3) the state of the thread kernel object becomes notified.
(4) if the thread is the last active thread in the process, the system also considers the process to have terminated.
(5) the usage count of the thread kernel object decreases by 1.
When a thread terminates its run, the kernel object is not automatically released until all unfinished references to the thread kernel object associated with it are closed.
Once a thread is no longer running, no other thread in the system can handle that thread's handle. However, other threads can call GetExitcodeThread to check that the thread identified by the hThread has terminated. If it has terminated, determine its exit code:
Function prototype:


BOOL GetExitCodeThread( 
HANDLE hThread, 
PDWORD pdwExitCode); 

The value of the exit code is returned in the DWORD that the pdwExitCode points to. If the thread is not terminated when the GetExitCodeThread is called, the function fills in DWORD with the STILL_ACTIVE identifier (defined as 0x103). If the function runs successfully, it returns TRUE.


Related articles: