Basic knowledge of threads 1. What are the differences and links between processes and threads? Each process requires at least one thread. The process consists of two parts: the process kernel object, address space. Threads are also composed of two parts: thread kernel objects, operating systems use it to implement threads. Thread stacks for maintaining all function parameters and local variables required when the thread is executing the code. The process is not lively. The process never performs anything, it is just a thread container. Threads are always created in a process environment, and its overall life is in this process. If in a single process environment, there are multiple threads being running, then these threads will share a single address space. These threads can perform the same code, operate the same data. These threads can also share the kernel object handle because the handle is dependent on each process rather than each thread. The system resources used by the process are much more than the thread. In fact, the thread has only one kernel object and a stack, and the reserved record is rare, so few memory is required. Therefore, you should always try to add threads to solve programming problems and avoid creating new processes. However, many program is designed to achieve more processes. 2. How to use the _beginthreadex function? The use method is the same as the CreateThread function, just calling the parameter type to be converted. 3. How do I use the CreateThread function? When CreateThread is called, the system creates a thread kernel object. The thread kernel object is not a thread itself, but an operating system used to manage the smaller data structure of the thread. Attention should be aware that the closehandle function to turn off the thread handle without calling the thread kernel. Since some C / C run library functions in the CreateThread function, there is a memory leak, so you should use it as much as possible. Parameter Meaning: LPTHREADATIADATTRIBUTES If the NULL is transmitted, the thread uses the default security properties. If all sub-processes can inherit the handle of the thread object, it must be initialized to TRUE. DWSTACKSIZE Sets the address space of the thread stack. If it is not 0, the function retains all memories and assigns the stack of threads. If it is 0, CreateThread retains a zone and assigns the memory capacity indicated by the link program embedded .EXE file / stack link. The memory capacity indicated to the thread stack. The address of the LPStartAddress thread function. LPPARAMETER passes the parameters of the thread function. DWCREATIONFLAGS If it is 0, the thread is scheduled immediately after being created. If it is CREATE_SUSPENDED, the system is suspended after initialization. LPTHREADID is used to store the ID of the system assigned to the new thread. 4. How to terminate the running of the thread? (1) The thread function returns (preferably use this method). This is the only way to ensure that all thread resources is correctly cleared. If the thread can return, you can ensure that the implementation of the following: All C objects created in the thread function will be properly revoked through their undo functions. The operating system will correctly release the memory used by the thread stack. The system sets the thread's exit code as the return value of the thread function. The system will decrease the usage count of the kernel object. (2) Call the exitthread function (preferably not to use this method). This function will terminate the running of the thread and cause the operating system to clear all operating system resources used by the thread. However, C resources (such as C class objects) will not be revoked. (3) Call the TerminateThread function (this method should be avoided). TerminateThread can undo any thread. The usage count of the kernel object of the thread is also reduced. The TerminateThread function is a function of asynchronous run.
If you want to know the thread is termination, you must call WaitForsingleObject or a similar function. The memory stack of the thread is also revoked when using the method returned or invoked to ExitTHREAD. However, if you use TerminateThread, the system does not undo the stack of the thread before you have threads terminate the run. (4) The process containing the thread is terminated (this method should be avoided). Since the entire process has been closed, all resources used by the process must have been cleared. Just like calling TerminateThread from each remaining thread. This means that the correct application clearance does not occur, that is, the C object revoked function is not called, the data is not transferred to disk, and the like. Once the thread is no longer running, there is no other thread to handle the handle of the thread in the system. However, other threads can adjust whether the thread identified by the HTHREAD is termination running. If it has been terminated, it determines its exit code. 5. Why don't you use the _beginthread function and _endthread function? Compared with the _beginthreadex function, there are few parameters and more limited. Unable to create a pause thread and cannot get the thread ID. The _endthread function has no parameters, and the thread exits the code must be 0. There is also the _endthread function to turn off the thread handle inside, once the exiting will not access the thread handle correctly. 6. How do I get a reference to the core of the process or thread? Handle getCurrentProcess (); Handle getCurrentThread (); these two functions can return a pseudo handle or a pseudo handle of a thread kernel object that calls a process. The fake handle can only be used in current processes or threads, and other threads or processes will not be accessible. The function does not create a new handle in the handle of the process. Calling these functions There is no impact on the usage count of the process or thread kernel object. If you call CloseHandle, transfer the fake handle as a parameter, then CloseHandle ignores the call of the function and returns false. DWORD getCurrentProcessId (); DWORD getCurrentThreadId (); these two functions allow threads to query the unique ID of its process or its own unique ID. 7. How to convert a fake handle to a consident handle? Handle HProcesstrue = NULL; Handle HthreadFalse = NULL; Handle Hthreadtrue = NULL;
hProcessFalse = GetCurrentProcess (); hThreadFalse = GetCurrentThread (); obtaining thread real handle: DuplicateHandle (hProcessFalse, hThreadFalse, hProcessFalse, & hThreadTrue, 0, FALSE, DUPLICATE_SAME_ACCESS); obtaining process real handle: DuplicateHandle (hProcessFalse, hProcessFalse, hProcessFalse, & hProcessTrue, 0 , False, duplicate_same_access); Since DuplicateHandle increases the use count of a specific object, it should be delivered to CloseHandle when the use of the copy object handle is completed, thereby reducing the use count of the object. 8. What is the maximum number of creative threads in a process? The maximum number of threads depends on the size of the available virtual memory of the system. The default can have a spatial space with up to 1MB of stacks. So, you can create 2028 threads. If the default stack is reduced, you can create more threads. Thread scheduling, priority, and intravinity 1. How to suspend and restore threads? The interior of the thread kernel object has a pause count of the thread. When the CreateProcess or CreateTHread function is called, the kernel object of the thread is created, and its pause count is initialized to 1. Because the thread is initialized for time, the thread cannot be started before the system is fully prepared. After the thread is fully initialized, createProcess or CreateTHRead wants to see if the create_suspended flag has been passed. If this flag has been passed, these functions return, and the new thread is paused. If this flag has not been passed, the function is reduced to 0. When the thread's pause count is 0, the thread is in a scheduled state unless the thread is waiting for other things. Creating a thread in the paused state, you can change the running environment (such as priority) that changes the thread before threading. Once you change the environment of the thread, you must make the thread become a scheduled thread. As follows: hThread = CreatThread (......, CREATE_SUSPENDED, ......); or bCreate = CreatProcess (......, CREATE_SUSPENDED, ......, pProcInfo); if (bCreate = FALSE!) {HThread = pProcInfo.hThread;} ......... ......... resumeThread (hthread); CloseHandle (hthread); ResumeThread success, it will return the previous pause count of the thread, otherwise returns 0xfffffffff. A single thread can be suspended several times. If a thread is suspended 3 times, it must restore 3 times. When you create a thread, in addition to using create_suspended, you can also call the SuspendThread function to suspend the operation of the thread. Any thread can call this function to suspend the operation of another thread (as long as you have a thread handle). Threads can be suspended from themselves, but they cannot recover their own. Like ResumeThread, SuspendThread returns the previous pause count of threads. The maximum number of thread pauses can be maximum_suspend_count. The execution of SUSPENDTHREAD and kernel mode is performed asynchronously, but the user's way of execution will not occur before the thread recovery runs.
Be careful when calling SuspendThread, because I don't know what it is to operate when the thread is running. Only know what the target thread is what the target thread is (or what is doing it) and taking powerful measures to avoid problems or deadlocks due to the operation of the thread, SuspendThread is safe. 2. Can I suspend and restore the operation of the process? For Windows, there is no concept of pause or recovery process, because the process never been arranged to obtain CPU time. However, Windows does allow a process to suspend all threads in another process, but the process of suspending operations must be a debugger. In particular, the process must call a function such as WaitFordeBuGevent and ContinueDebugevent. Due to competition, Windows does not provide other methods to pause all threads in the process. 3. How to use the SLEEP function? The system will make the thread in a usual millisecond. Windows is not a real-time operating system. Although threads may be woken up in the specified time, it can be done, depending on what operation is in progress. You can call SLEEP and pass Infinite for dwmilliseConds parameters. This will tell the system to never schedule the thread. This is not a thing worth doing. It is best to let thread exit and restore its stack and kernel objects. You can pass 0 to the SLEEP. This will tell the system that the calling thread will release the remaining time slice and force the system to schedule another thread. However, the system can re-scheduled threads just calling SLEEP. This happens if there is no adjustability thread with the same priority. 4. How to convert to another thread? The system provides the SwitchTothread function. When calling this function, the system wants to see if there is a thread that is urgently needed to be CPU time. If there is no thread urgently needs the CPU time, SwitchTothread will return immediately. If there is a thread that urgently needs the CPU time, SwitchTothRead scheduling the thread (the priority of the thread may be below the thread that calls SwitchTothread). This urgently requires the thread of the CPU time to run a time period, and then the system scheduling the program is often running. This function allows a thread that requires resources to force another priority, but currently has threads that have the resource abandon the resource. If there is no other thread to run when calling the SwitchTothRead function, then the function returns false, otherwise a non-0 value is returned. Calling SwitchTothRead is similar to calling Sleep. Differential SwitchTothread allows a lower priority thread operation; even if there is a low priority thread urgently need CPU time, SLEP can immediately re-scheduled call threads.
5. How to get the thread running time? (1) simply made thread about running time: DWORD dwStartTime = 0; DWORD dwEndTime = 0; DWORD dwRunTime = 0; dwStartTime = GetTickCount (); .................. dwEndTime = GetTickCount (); dwRunTime = dwEndTime - dwStartTime; ( 2) Call GetThreadTimes function: Parameter meaning: hthread thread handle LPCREATIONTIME creation time: British Greenwich Time LPEXITTIME Exit Time: British Greenwich Time The operating system code has passed how many 100ns of CPU time lpusertime user time: Indicate thread execution application code has passed how many 100ns of the CPU time getProceSstimes is a function similar to GetThreadTime, which is suitable for all threads in the process (even endless Running thread). The returned kernel time is the sum of all times of the thread of all processes in the kernel code. GetThreadTimes and getProceSstimes does not work in Windows 98. In Windows98, there is no reliable mechanism to determine how much CPU time has been used by a thread or process. 6. What are the priority classes of the process? The priority class identifier describes real-time realTIME_PRIORITY_CLASS to respond to events, perform critical time tasks. Will be prior to operating the system components. High high_priority_class immediately responds to the event, performs the task of critical time. It is higher than normal from normal ABOVE_NORMAL_PRIORITY_CLASS running between normal priority and high priority (Windows2000). Normal normal_priority_class does not have special scheduling requirements lower than normal BELOW_NORMAL_PRIORITY_CLASS runs between normal priority and idle priority (Windows2000). Idle IDLE_PRIORITY_CLASS runs when the system is idle. Setting method: Bool SetPriorityClass (Handle HProibility); DWORD getPriorityClass (Handle HProcess); When you start a program with a command housing, the starting priority of the program is normal priority. If you use the start command to start the program, you can use a switch to set the initial priority of the application. For example: c: /> start / low calc.exestart command can also identify / Belownormal, / Normal, / Abovenormal, / High, and / RealTime and other switches. 7. What are the relative priorities of thread? Relative priority identifier Description Key Time THREAD_PRIRITY_TIME_CRITIL Run on the real-time priority class thread in priority 31, threads run on priority 15 for other priority classes. The highest Thread_Priority_Highest thread runs at two levels above normal priority. It is higher than the normal thread_priority_above_normal thread runs on the normal priority. Normal thread_priority_normal thread runs normally on the priority class of the process. Lower than normal thread_priority_below_normal threads running below normal priority.
The lowest thread_priority_lowest thread runs at two levels below normal priority. Idle Thread_Priority_Idle runs on the priority 16 for other priority class threads on priority 1 for real-time priority class threads. Setting method: BOOL setthread, DWord dword dword dword dword dword dword getthreadPriorityClass (Handle Hthread); 8. How to avoid system dynamics improve thread priority level? The system often improves the priority level of threads to respond to I / O events such as window messages or read disks. Or when the system finds a thread that has always been eager to get the CPU time in about 3 to 4s, it will increase this eager to get the priority of the thread of the CPU time to 15, and let the thread run twice the amount of time. When it is doubled, the priority of the thread returns to its basic priority. The following function can be provided to the scheduling system: BOOL SetProcessPriorityBoost (HANDLE hProcess, BOOL bDisableBoost); BOOL GetProcessPriorityBoost (HANDLE hProcess, PBOOL pbDisableBoost); BOOL SetThreadPriorityBoost (HANDLE hThread, BOOL bDisableBoost); BOOL GetThreadPriorityBoost (HANDLE hThread, PBOOL pbDisableBoost ); SetProcessPriorityBoost is responsible for telling the system to activate or deactivate all threads in progress, while SETHREADPRIRIRITYBOOST activates or disables the priority improvement of each thread. Windows98 does not provide useful implementation code for these four functions. Synchronization of threads in user mode 1. Only one statement does not need to consider thread synchronization? When programming with advanced languages, we tend to be a statement that is the smallest atomic access, and the CPU does not run other threads in this statement. This is wrong, because even if a very simple statement is compiled, it may become multi-line code after compiling the compiler. Therefore, thread synchronization must be considered. No thread should modify the shared variable by calling a simple C statement. 2. Does the interlocking function? (1) long interlockedexchangeAdd (LPLONG ADDEND, Long Increment); Addend is the address of a long-integer variable, which is incremented by the value (can be negative) to the long-intensive variable you want to point to Addend. The main role of this function is to ensure that this add operation is an atomic access. (2) Long InterlocKedexchange (LPLONG TARGET, LONG VALUE); Dissipate the value pointing to the first parameter with the value of the second parameter. Function return value is the original value. (3) PVOID InterlocKedexchangePointer (PVOID * TARGET, PVOID VALUE); reckon the value pointing to the first parameter with the value of the second parameter. Function return value is the original value. (4) Long InterlockedCompareExchange (LPLONG DESTINATION, Long Exchange, Long Compera); if the third parameter is the same as the value points to the first parameter, then the first parameter pointing to the value indicated by the second parameter. Function return value is the original value.
(5) Pvoid InterlockedCompareExchangePointer (PVOID * DESTINATION, PVOID EXCHANGE, PVOID Comperand); if the third parameter is the same as the value points to the first parameter, then the first parameter points to the value indicated by the first parameter. Function return value is the original value. 3. Why should the single CPU computer should not use a loop lock? Exemplified: BOOL g_bResourceUse = FALSE; ...... void ThreadFunc1 () {BOOL bResourceUse = FALSE; while (1) {bResourceUse = InterlockedExchange (& g_bResourceUse, TRUE); if (bResourceUse == FALSE) {break;} Sleep (0); } ................ InterlockedExchange (& g_bresourceuse, false);} First loop lock will waste CPU time. The CPU must constantly compare two values until a value is "wonderfully" changed due to another thread. And the thread using this loop lock should be the same priority, and the SETTHREADPRIORITYBOOST function or the setthreadPriorityBoost function is used to disable the dynamic improvement of the thread priority, otherwise the lower priority thread may never be called. 4. How do I use the volatile declared variable? If you are using the address of the shared resource, you can use the Volatile, because the function must read this value from the memory when a variable address is passed to a function. Optimization procedures do not have any impact on it. If you use the variables directly, you must have a qualified word of the Volatile type. It tells the compiler, and the variable can be modified by an application other than the application itself, which includes operating systems, hardware, or threads that are executed simultaneously. The Volatile Limit word will tell the compiler, do not perform any optimization of the variable, and always reload the value of the memory cell from the variable. Otherwise, the compiler stores the value of the variable into the CPU register and operates the register each time. The thread will enter an infinite loop and will never be awake. 5. How do I use the key code segment to implement thread synchronization? If a small piece of code is required in an atomic operation, the simple interlock function can no longer meet the needs, and the key code segment must be used to solve the problem. However, when using a critical code segment, it is easy to fall into a deadlock state because the timeout value cannot be set when waiting for the critical code segment. The key code segment is implemented by setting a flag to the shared resource, just like the "someone / no one" mark on the toilet door. This logo is a critical_section variable. This variable should be initialized before any thread uses it. Initialization can have two methods, using the initializecriticalsection function and the initializecriticalsectionandspincount function. Then before each critical code segment using a shared resource or use the TryEntercriticalSECTION function. Call the LeaveCriticalSECTION function after using the key code segment. The DeleteCriticalSECTION function should be called to clear the flag after all threads use this shared resource. Example: const Int max_times = 1000; int g_intINDEX = 0; dword g_dwtimes [max_times]; critical_section g_cs; void init () {... initializecriticalsection; ......}
DWORD WINAPI FirstThread (PVOID lpParam) {while (g_intIndex Void Close () {... deletecriticalsection; ......} You should pay attention to some tips using the key code segment: (1) Each shared resource uses a critical_section variable. This allows another resource to be occupied by other threads when the current thread has a resource. EnterCriticalSection (& g_cs); for (intLoop = 0; intLoop <100; intLoop ) {g_intArray [intLoop] = 0; g_uintArray [intLoop] = 0;} LeaveCriticalSection (& g_cs); to: EnterCriticalSection (& g_csInt); for (intLoop = 0; intLoop <100; intLoop ) {g_intArray [intLoop] = 0;} LeaveCriticalSection (& g_csInt); EnterCriticalSection (& g_csUint); for (intLoop = 0; intLoop <100; intLoop ) {g_uintArray [intLoop] = 0;} LeaveCriticalSection ( & g_csuint); (2) Accessing multiple resources at the same time must always request access to resources in the same order. This will avoid the occurrence of deadlock. There is no relationship in the order of leave. Thread1: EnterCriticalSection (& g_csInt); EnterCriticalSection (& g_csUint); for (intLoop = 0; intLoop <100; intLoop ) {g_uintArray [intLoop] = g_intArray [intLoop];} LeaveCriticalSection (& g_csInt); LeaveCriticalSection (& g_csUint); Thread2: EnterCriticalSection ( & g_csUint); EnterCriticalSection (& g_csInt); for (intLoop = 0; intLoop <100; intLoop ) {g_uintArray [intLoop] = g_intArray [intLoop];} LeaveCriticalSection (& g_csInt); LeaveCriticalSection (& g_csUint); to: Thread1: EnterCriticalSection (& g_csInt ); EnterCriticalSection (& g_csUint); for (intLoop = 0; intLoop <100; intLoop ) {g_uintArray [intLoop] = g_intArray [intLoop];} LeaveCriticalSection (& g_csInt); LeaveCriticalSection (& g_csUint); Thread2: EnterCriticalSection (& g_csInt); EnterCriticalSection ( & g_csUint); for (intLoop = 0; intLoop <100; intLoop ) {g_uintArray [intLoop] = g_intArray [intLoop];} LeaveCriticalSection (& g_csInt); LeaveCriticalSection (& g_csUint); (3) do not run time critical code segments. EnterCriticalSection (& g_cs); SendMessage (hWnd, WM_SOMEMSG, & g_s, 0); LeaveCriticalSection (& g_cs); to: EnterCriticalSection (& g_cs); sTemp = g_s; LeaveCriticalSection (& g_cs); SendMessage (hWnd, WM_SOMEMSG, & sTemp, 0); 6 InitializeCriticalSECTION / INITIALIZECRITICSECTIONANDSPINCOUNT difference? The return value of the INITIALIZECRITICALSECTION function is empty and does not create an event kernel object, which compares system resources, but once two or more threads are strive for critical code segment, if memory is insufficient, the key code segment may be strive, at the same time The system may not be able to create the necessary event kernel objects. At this time, the EntercriticalSECTION function will generate an exception_invalid_handle exception. This error is very rare. If you want to prepare this situation, you can have two options. An error can be tracked using a structured abnormality processing method.