1. The process has two components, a process kernel object and an address space. Threads also have two components:
- A kernel object that is a thread that the operating system uses to manage threads. The system also uses kernel objects to store thread statistics.
- A line stacks that maintains all the function parameters and local variables required for thread execution.
2. Threads execute code and process data within the address space of their processes, and if more than two threads in a process context are running, they share an address space. These threads can execute the same code and work with the same data. In addition, these threads share kernel object handles because the handle table is for each process.
3. Creating a virtual address space for a process requires a large amount of system resources, a large amount of logging activity occurs, which requires a lot of memory, and because the. exe and. dll files are loaded into an address space, all require file resources. While threads have only one kernel object and one stack, there is almost no record activity involved, all of which do not need to occupy much memory.
4. When the thread function terminates, the memory used for the line stacks is also freed, the usage count of the thread kernel object is decremented, and it becomes 0 o'clock destroyed.
5. The system allocates memory from the process's address space to the thread stack, and the new thread runs in the same process context as the thread responsible for creating it. Therefore, the new thread can access all the handles of the process kernel object, all the memory in the process, and the stack of all the other threads in the same process.
6. When calling CreateThread, the predetermined address space capacity sets the upper limit of the stack space in order to capture infinite recursive bugs in the code. Otherwise, all the address space of the process is allocated and a large amount of physical storage is allocated for the thread stack.
7. Threads can terminate the operation in the following 4 ways.
- Thread function return (highly recommended)
- The thread "kills" itself by calling the ExitThread function (avoid using this method)
- Call the TerminateThread function on the same process or thread in another process (avoid using)
- Processes that contain threads terminate run (avoid use)
8. Let the thread function return to ensure that the following correct application cleanup work is performed.
- All C + + objects created in a thread function are destroyed correctly by their destructors.
- The operating system correctly frees the memory used by the thread stack.
- The operating system sets the exit of the thread (maintained in the kernel object of the thread) to the return value of the threading function.
- The system recursively reduces the usage count of the thread's kernel objects.
The 9.ExitThread function terminates the running of the thread and causes the operating system to clean up all operating system resources used by that thread. However, C + + resources, such as C + + class objects, are not destroyed.
10.ExitThread is to kill the keynote thread, and TerminateThread can kill any thread. The TerminateThread is asynchronous and is not guaranteed to be terminated when returned. And with this function, the system does not destroy the thread's stack unless the process that owns the thread terminates.
11. dynamic-link library DLLs typically receive notifications when a thread terminates the runtime, but the DLL does not receive this notification if the TerminateThread is called to kill the threads.
12. When a thread terminates running, these things happen
- All user object handles that are owned by the thread are freed. In Windows, most objects are owned by the process that contains the threads that create these objects. But a thread has two user objects: Windows and hooks. When a thread terminates the runtime, any Windows created or installed by the thread are automatically destroyed, and any hooks created or installed by the thread are unloaded, and the other objects are destroyed only when the thread-owning process terminates.
- The exit code for the thread changes from still_active to Iexitthread or TerminateThread.
- The state of the thread kernel object becomes the trigger state.
- If the thread is the last active thread in the process, the system considers the process to be terminated as well.
- The usage count of thread kernel objects is decremented by 1.
13. When a thread terminates running, its associated thread object is not automatically freed, unless all non-closed references to the object are closed.
14. Once the thread is no longer running, there is no other thread in the system to use the handle of the thread, but other threads can call GetExitCodeThread to check whether the thread terminates the run and its exit code.
15. A call to the CreateThread function causes the system to create a thread kernel object. The object's initial usage count is 2. Other properties are also initialized. Once the kernel object is created, the system allocates memory for use by the thread's stack. This memory is allocated from the address space memory of the process because the thread does not have its own address space. The system then writes the Pvparam and PFNSTARTADDR parameters to the first and second values of the line stacks.
16. 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 was last executed. The CPU registers of the threads are all saved in a context structure. The context structure holds the thread kernel object,
17. The instruction register and the stack pointer register are the most important two registers in the thread context. Remember that threads always run in the context of the process, so the memory identified by the two addresses is in the address space of the process where the thread resides. When the thread kernel object is initialized, the context structure's stack pointer register is set to the address in the PFNSTARTADDR threads stack. The instruction register is set to the address of the Rtluserthreadstart function.
VOID Rtluserthreadstart (pthread_start_routine pfnstartaddr, PVOID pvparam) { __try { ExitThread ( PFNSTARTADDR) (Pvparam)); } __except (UnhandledExceptionFilter (GetExceptionInformation ())) { exitprocess (GetExceptionCode ()); } // Note:we never gethere}
18.RtlUserThreadStart is actually where threads begin to execute. Two parameters are displayed by the operating system to the thread stack instead of being called from another function. When the new thread executes the Rtluserthreadstart function, the following things will happen:
- Around the thread function, a structured exception-handling frame is set. As a result, any exceptions that are generated during thread execution can be handled by default on the system.
- The system calls the thread function and passes it to the Pvparam parameter passed to the CreateThread function.
- When the thread function returns, Rtluserthreadstart calls ExitThread and passes the return value of your thread function to it. The usage count of the thread kernel object is decremented, and then the thread stops executing.
- If the thread produces an unhandled exception, the SEH frame set by the Rtluserthreadstart function handles the exception. Typically, this means that a message box is displayed to the user, and when the user closes the message box, Rtluserthreadstart calls ExitProcess to terminate the entire process, rather than just terminating the problematic thread.
Within Rtluserthreadstart, threads call ExitThread or exitprocess. This means that the thread can never exit this function.
20. When Rtluserthreadstart calls your thread function, it presses the return address of the thread function onto the stack, allowing the thread function to know where to return. However, the Rtluserthreadstart function is not allowed to return. If it does not attempt to return without forcing the "kill" thread, it will almost certainly cause an access violation because there is no function return address on the thread stack, and Rtluserthreadstart will attempt to return a random memory location.
21. When the main thread of a process is initialized, its instruction pointer is set to the same non-documented function Rtluserthreadstart, and when Rtluserthreadstart begins execution, it invokes the startup code of the C + + runtime, which initializes and then calls your _ The Tmain or _tWinMain function. When your entry point function returns, the C + + run-time startup code calls ExitProcess. Therefore, the main thread will never return to the Rtluserthreadstart function for C + + applications.
The 22.VS comes with 4 C + + runtime libraries for native code development, and two library-to-microsoft.net managed environments. Note that all of these libraries support thread development and no longer have a separate C/D + + library dedicated to single-threaded development.
23. Since the standard C run-time library was invented around 1970, the concept of threading occurs on the operating system long after, so multithreaded applications using the C run-time library can have problems, such as setting global variables such as errno.
24. When creating a new thread, be sure not to invoke the operating system's CreateThread function. Instead, you must call the C + + Runtime library function _beginthreadex.
25. For the _beginthreadex function, you need to focus on the following points:
- Each thread has its own dedicated _tiddata memory block, which is allocated from the heap on the C + + runtime library.
- The address of the thread function passed to _beginthreadex is stored in the _tiddata memory block.
- _beginthreadex does call CreateThread internally, because the operating system only knows how to create a new thread in this way.
- When the CreateThread function is called, the function address passed to it is _threadstartex (not pfnstartaddr). In addition, the parameter address is the address of the _TIDDATA structure, not the pvparam.
- If all goes well, it returns a handle to the thread, just like CreateThread. Any operation that fails will return 0.
26. About the Threadstartex function, and its focus:
- The new thread executes Rtluserthreadstart first, and then jumps to _threadstartex.
- Threadstartex the only parameter is the address of the new thread's _tiddata memory block.
- TlsSetValue is an operating system function that associates a value with the keynote thread, which is called thread-local storage. The Threadstartex function associates the _TIDDATA memory block with the new thread.
- In a parameterless auxiliary function, _callthreadstartex, there is an seh frame that encloses the thread function that is expected to execute. This frame handles many things related to the runtime, such as run-time errors (such as throwing a C + + exception that is not caught), and the signal function of the C + + runtime library. This is important if you create a new thread with the CreateThread function and then call the signal function of the C + + runtime, the signal function does not work correctly.
- The thread function that is expected to execute is called and passes the expected parameters to it.
- The return value of the thread function is considered to be the exit code of the thread. But note that Callthreadstartex is not simply returned to _threadstartex, and then to Rtluserthreadstart, if that is the case, the thread terminates and its exit code is set correctly, but the thread's _ Tiddata memory blocks are not destroyed. This causes the application to have a memory leak. To prevent this problem, _threadstartex invokes the _endthreadex and passes the exit code to it.
27. For the _endthreadex function, the following points need to be noted:
- The C run-_getptd_noexit function internally invokes the operating system's TlsGetValue function, which gets the Tiddata memory block address of the main thread.
- _endthreadex then releases this block of data and invokes the operating system's ExitThread function to actually destroy the thread. Of course, it will pass and set the exit code correctly.
28. When a thread calls a _tiddata-C + + Runtime library function that needs to be structured:
- First, C + + runtime functions attempt to get the address of the thread data block (by calling TlsGetValue).
- If NULL is returned as the address of the _tiddata block, the thread does not have a _tiddata block associated with it. At this point, the C + + runtime function allocates and initializes a _tiddata block for the keynote thread.
- The block is then associated with the thread (through TlsSetValue), and as long as the thread is still running, the block will persist and be associated with the thread.
- You can now use the _tiddata block of a thread for C + + run-time library functions, which can also be used by any of the C + + runtime libraries that are called later.
29. In fact, for the above process, the problem is that if the thread uses the signal function of the C + + runtime, the entire process terminates because the structured exception handling (SEH) frame is not ready to cause a memory leak. The second problem is that if a thread is not terminated by calling _endthreadex, the database cannot be destroyed, causing a memory leak.
30. When the module is connected to the DLL version of the C + + runtime library, the library receives a DLL_THREAD_DETACH notification when the thread terminates, and releases the _tiddata block, which prevents the _tiddata block from leaking, but avoids using it as much as possible.
The 31._endthread function is parameterless, meaning that the exit code of the thread is hardcoded to 0, and it calls the ExitThread before calling CloseHandle, passing it a handle to the new thread.
32.Windows provides a number of functions to make it easier for a thread to reference its process kernel object or its own thread kernel object: GetCurrentProcess () GetCurrentThread (). Both functions return a pseudo-handle to the process kernel object or thread kernel object of the keynote thread. Calling these two functions does not affect the usage count of the process kernel object or thread kernel object. Calling CloseHandle ignores this call and returns FALSE. Note that the pseudo handle is a handle to the current thread, that is, the thread that issued the function call. Can be converted to a real handle with DuplicateHandle.
33.
Windows Internals Notes--Threads