Chapter 3 -- execution unit of Win32 Program (partial concepts and code explanation) (Chapter 3 -- win32
Learn the Windows program design record
Concept tips:
1.The thread describes the execution path of the Code in the process.
2. _ stdcall is the call method of the new standard C/C ++ function. At the underlying layer, the stack-to-stack sequence of calling method parameters is the same as that of standard C call (_ cdecl method), but _ stdcall uses the automatic stack clearing method, _ cdecl uses the manual stack clearing method.
3. Windows stipulates that all functions called by them are defined as _ stdcall. ThreadProc is a callback function that is called by the Windows system. Therefore, this function should be defined as _ stdcall. In addition, when no explicit description is provided, the default function call method is _ cdecl.
4. The CreateThread function is used to create a new thread. The thread created by this function will be executed in the caller's virtual address space. After the function is successfully executed, the thread handle of the new thread is returned.
5. The WaitForSingleObject function is used to wait for the specified object (hHandle) to become a trusted state. The dwMilliseconds parameter specifies the wait time in milliseconds. If it is set to INFINITE, it indicates that it takes an INFINITE period of time to wait.
PS: WaitForSingleObject (
HThread, // handle to wait for the object
INFINITE // wait time (in milliseconds)
);
6. when the following conditions occur, the WaitForSingleObject function will return:
1) the object to be waited changes to the signaled state;
2) the time specified by the dwMilliseconds parameter has passed.
PS: an executable object has two states: nonsignaled and signaled. The thread object is in the trusted State only when the thread stops running.
7. When a child process is created, if TRUE is passed to the bInheritHandles parameter of the CreateProcess function, the child process can inherit the inherited handle of the parent process.
8. dwCreationFlags -- create a flag. If the value is 0, it indicates that the thread starts execution immediately after being created. If it is specified as create_suincluded, it indicates that the thread is suspended after being created, that is, paused, until the thread is started explicitly using the ResumeThread function.
9. The thread kernel object can be said to be a data structure containing the thread state information. The management thread functions provided by the system are managed by accessing the thread kernel objects.
Chart: CONTEXT (CONTEXT, that is, the register status)
EAX
EBX
Other CPU registers
Usage Count (2)
Suspend Count pause Count (1)
Exi Code exit Code (STILL_ACTIVE)
Whether Signaled is trusted (FALSE)
............
10. Thread context: Each thread has its own set of CPU registers, called the thread context.
11. Usage: The Usage Count member records the Usage of the thread kernel object. This Count indicates the number of times the kernel object is opened. As long as the thread is not running, the value of this count is at least 1. When creating a new thread, the CreateThread function returns the handle of the thread kernel object, which is equivalent to opening a newly created kernel object. This will also promote the value of Usage Count to 1. Therefore, after creating a new process, the value of Usage Count in the initial state is 2. Then, as long as a process opens this kernel object, it will increase the value of Usage Count by 1. Since the call to the OpenThread function adds the value of Usage Count to 1, you must use the CloseHandle function to close the returned handles. (If the handle is not closed, memory leakage may occur. Of course, after the process of the thread ends, all resources occupied by the process will be released .) Once a thread function is returned, the thread's life cycle ends.
12. Pause Count: The Suspend Count in the thread kernel object is used to specify the number of thread pauses. When creating a thread, you can specify the create_suincluded flag to change the running environment of the thread before executing any code. (For example, priority .) The ResumeThread function (wake up a suspended thread) reduces the number of thread pauses. Note that a thread can be paused several times. If a thread is paused three times, it must be awakened three times before it can be allocated to a CPU. Any thread can call the SuspendThread function to pause the running of another thread. This function can increase the number of thread pauses.
13. Exit Code: the Exit Code of the Member specifies the Exit Code of the thread, or the return value of the thread function. You can also use the GetExitCodeThread function to obtain the exit code of a thread.
14. Trusted: The member Signaled specifies whether the thread object is in the "trusted" state. When the thread is running, the value of Signaled is always FALSE, that is, "untrusted ". The value of Signaled is set to TRUE only when the thread ends.
15. Thread termination: When the thread terminates normally, the following events occur:
1) All C ++ objects created in the thread functions will be correctly destroyed through their respective destructor.
2) The stack used by this thread will be released.
3) The system sets the Exit Code value in the thread kernel object from STELL_ACTIVE to the return value of the thread function.
4) The system will decrease the Usage Code (count used) value in the thread kernel object.
16. There are four methods to terminate the thread execution.
1) The thread function exits naturally. When the return statement is returned when the function is executed, Windows terminates the thread execution. We recommend that you use this method to terminate thread execution.
2) use the ExitThread function to terminate the thread. This function will abort the current thread and urge the system to release all resources used by the thread, but the C/C ++ resources cannot be correctly understood. Here is an example of destructor, which will not be shown.
3) use the TerminateThread function to forcibly terminate the execution of another thread in one thread. Note that this is a function that is strongly recommended to avoid. Once this function is executed, the program will not be able to predict where the target thread is terminated, which may cause the target thread to have no chance to clean up, for example, the memory occupied by opening files will not be released. In addition, when the function is used to terminate a process, the system will not release the stack used by the thread.
4) use the ExitProcess function to terminate the process. The system automatically ends the running of all threads in the process. However, this method is equivalent to using the TerminateThread function for each thread, So we strongly recommend that you avoid it.
PS: Every thread should let it exit normally, that is, it is returned by its thread function. There are many ways to notify the thread to exit, such as using event objects and setting global variables.
17. thread priority: Each thread must be assigned a priority number ranging from 0 (lowest) to 31 (highest ).
18. Windows supports six priority classes: idle, below normal, normal, above normal, high, and real-time. A process belongs to a priority class and can also assign a relative thread priority to the threads in the process. When a thread is created, its relative priority is always set to normal. (It indicates that I modified the process priority when extracting the file, and I don't feel that the speed is faster. Sorrow .)
19. The SetThreadPriority (HANDLE hThread, int nPriority) function is used to set the thread priority. In the parameter, the former is the target thread handle, and the latter defines the priority of the thread. (The following example shows the priority: PriorityDemo .)
20. Common method for changing the thread priority in actual programming: when creating a thread, the create_suincluded mark is passed to the CreateThread function, which can cause the new thread to be paused. Set its priority to the desired priority. Then, call the ResumeThread function to restore the thread.
21. The WaitForMultipleObjects function is used to wait for Multiple kernel objects. (This is shown in the instance PriorityDemo .)
22. The threads in the Windows Explorer process run at a high priority. (Do not associate it with IE. The Explorer here refers to the Windows program manager or file resource manager, which can be said to be the core of the graphic interface. Don't ask why I know this clearly, because I have disabled this process .)
23. In actual development, generally, the CreateThread function provided by Windows is not used to create a thread, but the function _ beginthreadex in the C/C ++ Runtime is used. (Note: The default C/C ++ Runtime Library of VC does not support the _ beginthreadex function. .) Correspondingly, the C/C ++ Runtime Library also provides another function -- _ endthreadex used to end the current thread, which is used to replace the ExitThread function.
Code explanation:
1. ThreadDemo
PS: the main thread first creates a secondary thread, prints the ID number of the secondary thread, and waits until the execution of the secondary thread ends. The secondary thread prints only a few lines of strings to simulate real work.
1 # include <stdio. h> 2 # include <windows. h> 3 4 // thread function 5 dword winapi ThreadProc (LPVOID lpParam) 6 {7 int I = 0; 8 while (I <20) 9 {10 printf ("I am from a thread, count = % d \ n", I ++); 11} 12 return 0; 13} 14 15 int main (int argc, char * argv []) 16 {17 HANDLE hThread; 18 DWORD dwThreadId; 19 20 // create a thread 21 hThread = :: createThread (22 NULL, // Default Security Attribute 23 NULL, // default stack size 24 ThreadProc, // thread entry address (Execution thread function) 25 NULL, // The 26 0 parameter passed to the function, // specify the thread to run 27 & dwThreadId) immediately; // return the thread ID 28 printf ("Now another thread has been created. ID = % d \ n ", dwThreadId); 29 30 // wait for the end of the new thread to run 31: WaitForSingleObject (hThread, INFINITE); 32: CloseHandle (hThread ); 33 return 0; 34}
2. PriorityDemo
PS: The following program creates two threads at the same time. The priority of one Thread is "Idle", and the "Idle Thread is running" string is continuously printed during running; the priority of another Thread is "Normal". During running, the "Normal Thread is running" character is printed continuously.
1 # include <stdio. h> 2 # include <windows. h> 3 4 dword winapi ThreadIdle (LPVOID lpParam) 5 {6 int I = 0; 7 while (I ++ <10) 8 printf ("Idle Thread is running \ n"); 9 10 return 0; 11} 12 13 dword winapi ThreadNormal (LPVOID lpParam) 14 {15 int I = 0; 16 while (I ++ <10) 17 printf ("Normal Thread is running \ n"); 18 19 return 0; 20} 21 int main (int argc, char * argv []) 22 {23 DWORD dwThreadID; 24 HANDLE h [2]; 25 26 // Create a thread with the Idle priority 27 h [0] =: CreateThread (NULL, 0, ThreadIdle, NULL, 28 create_suincluded, & dwThreadID); 29 :: setThreadPriority (h [0], THREAD_PRIORITY_IDLE); 30: ResumeThread (h [0]); 31 32 // create a thread with a Normal priority 33 h [1] = :: createThread (NULL, 0, ThreadNormal, NULL, 34 0, & dwThreadID); 35 36 // wait for the kernel objects of both threads to change to a trusted state 37: WaitForMultipleObjects (38 2, // DWORD nCount: the number of kernel objects to wait for 39 h, // const handle * lpHandles HANDLE array 40 TRUE, // BOOL bWaitAll specifies whether to wait for all kernel objects to become trusted 41 INFINITE); // DWORD dwMilliseconds wait time 42 43: CloseHandle (h [0]); 44: CloseHandle (h [1]); 45 46 return 0; 47} 48 49/* 50 HANDLE h [2]; 51 h [0] = hThread1; 52 h [1] = hThread2; 53 DWORD dw =:waitformultipleobjects (2, h, FALSE, 5000); 54 switch (dw) 55 {56 case WAIT_FAILED: 57 // failed to call the WaitForMultipleObjects function (the handle is invalid ?) 58 break; 59 case WAIT_TIMEOUT: 60 // No Kernel Object received 61 break within 5 seconds; 62 case WAIT_OBJECT_0 + 0: 63 // handle h [0] the corresponding kernel object is trusted 64 break; 65 case WAIT_OBJECT_0 + 1: 66 // handle h [1] The corresponding kernel object is trusted 67 break; 68} 69 */