After Process, Few basics about Thread. This is my summary note from my diary: Source: Programming Application for Microsoft Windows by Jeffrey Richter.
Thread Introduction.
Like a process kernel object and an address space, a thread consists of two components:
A kernel object that the operating system uses to manage the thread. The kernel object is also where the system keeps statistical information about the thread.
A thread stack that maintains all the function parameters and local variables required as the thread executes code.
How exactly Process and Thread works:
When a thread calls CreateProcess, the system creates a process kernel object with an initial usage count of 1. This process kernel object is not the process itself but a small data structure that the operating system uses to manage the process—process kernel object as a small data structure that consists of statistical information about the process. The system then creates a virtual address space for the new process and loads the code and data for the executable file and any required DLLs into the process's address space.
The system then creates a thread kernel object (with a usage count of 1) for the new process's primary thread. Like the process kernel object, the thread kernel object is a small data structure that the operating system uses to manage the thread. This primary thread begins by executing the C/C++ run-time startup code, which eventually calls your WinMain, wWinMain, main, or wmain function. If the system successfully creates the new process and primary thread, CreateProcess returns TRUE.
Points to know about Thread:
Every thread must have an entry-point function where it begins execution.
Entry-point function for primary thread: main, wmain, WinMain, or wWinMain.
If you want to create a secondary thread in your process, it must also have an entry-point function, which should look something like this:
DWORD WINAPI ThreadFunc(PVOID pvParam){
DWORD dwResult = 0;.
.......
.......
return(dwResult);
}
Thread function can perform any task you want it to. Ultimately, thread function will come to an end and return. At this point, your thread stops running, the memory for its stack is freed, and the usage count of your thread's kernel object is decremented. If the usage count becomes 0, the thread kernel object is destroyed. Like process kernel objects, thread kernel objects always live at least as long as the thread they are associated with, but the object might live well beyond the lifetime of the thread itself.
Unlike a primary thread's entry-point function, which must be named main, wmain, WinMain, or wWinMain, a thread function can have any name. In fact, if you have multiple thread functions in your application, you have to give them different names or the compiler/linker will think that you've created multiple implementations for a single function.
Thread function must return a value, which becomes the thread's exit code.
Thread function (and really all functions) should try to use function parameters and local variables as much as possible. When you use static and global variables, multiple threads can access the variables at the same time, potentially corrupting the variables' contents. However, parameters and local variables are created on the thread's stack and are therefore far less likely to be corrupted by another thread.
Terminating a Thread
A thread can be terminated in four ways:
The thread function returns. (This is highly recommended.)
VOID ExitThread(DWORD dwExitCode);
This function terminates the thread and causes the operating system to clean up all of 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.
The thread kills itself by calling the ExitThread function. (Avoid this method.)
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.
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.
A thread in the same or in another process calls the TerminateThread function. (Avoid this method.)
The ExitProcess and TerminateProcess functions terminate threads. The difference is that these functions terminate all the threads contained in the process being terminated. Also, since the entire process is being shut down, all resources in use by the process are guaranteed to be cleaned up.
Some Thread Internals :
A call to CreateThread causes the system to create a thread kernel object. This object has an initial usage count of 2.
Other properties of the thread's kernel object are also initialized: the suspension count is set to 1, the exit code is set to STILL_ACTIVE (0x103), and the object is set to the nonsignaled state.
Once the kernel object has been created, the system allocates memory, which is used for the thread's stack. This memory is allocated from the process's address space since threads don't have an address space of their own.
The system then writes two values to the upper end of the new thread's stack.The first value written to the stack is the value of the pvParam parameter that you passed to CreateThread. Immediately below it is the pfnStartAddr value that you also passed to CreateThread.
Each thread has its own set of CPU registers, called the thread's context. The context reflects the state of the thread's CPU registers when the thread last executed. The set of CPU registers for the thread is saved in a CONTEXT structure (defined in the WinNT.h header file).
The CONTEXT structure is itself contained in the thread's kernel object.
The instruction pointer and stack pointer registers are the two most important registers in the thread's context.
When the thread's kernel object is initialized, the CONTEXT structure's stack pointer register is set to the address of where pfnStartAddr was placed on the thread's stack. The instruction pointer register is set to the address of a function called BaseThreadStart. This function is contained inside the Kernel32.dll module
No comments:
Post a Comment