Win32 process and thread concept
The process is an executable program that consists of private virtual address space, code, data, and other operating system resources (files, pipes, synchronization objects, etc.). An application can have one or more processes, one process can have one or more threads, one of which is the main thread.
The thread is an operating system to schedule a basic entity that assigns a CPU time. A thread can execute the code of any part of the program, even if this part of the code is executed in parallel by another thread; all threads of a process share its virtual address space, global variables, and operating system resources.
The reason why this concept is because threads rather than the process is more efficient:
Since the creation of the new process must load the code, the code to be executed has been mapped to the address space of the process, so created, the speed of the thread is faster than the process. All threads of a process share the address space and global variables of the process, so simplifying communication between threads.
Win32 process processing description Because the MFC does not provide a class processing process, the Win32 API function is used directly.
The Create Create Create Create Process function creates a new process and runs the specified program. CreateProcess following prototype: BOOL CreateProcess (LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation); wherein: lpApplicationName points included to run the module name String. LPCommandline points to the command line string. LPPRocessAttributes Description Process security properties, useful under NT. LPTHREADATTRIBUTES Description Process initial thread (main thread) security properties, useful under NT. BinheritHandles indicates whether the child process (the process created) can inherit the handle of the Parent process. The handle can be inherited with a thread handle, a famous or unnamed pipe, a mutually exclusive object, an event, a signal amount, an image file, a normal file, and a communication port. There are also some handles that cannot be inherited, such as memory handles, DLL instance handle, GDI handle , Ureer handle, etc. The handle inherited by the child process is passed by the parent process through the command line method or the process communication (IPC) mode. DWCREATIONFlags represents the type of priority category and process for creating a process. Create a process of the process, debugging process, etc .; the priority category is used to control the priority level of the process, divided by IDLE, NORMAL, HIGH, REAL_TIME. LpenViroment points to the environment variable block, the environment variable can inherit the sub-process. LPCurrentDirectory points to the string representing the current directory, and the current directory can inherit. LPStartupInfo points to the StartupInfo structure, the appearance of the main window of the process. LPPROCESSINFORMATION points to the Process_information structure to store the returned process information. From its parameters, you can see what information is required to create a new process. As can be seen from the above explanation, a process contains a lot of information. If the process creates success, return a pointer to a process information structure type. The process information is as follows: typedef struct _process_information {handle hndle hprocess; handle hthread; dword dwthread;} process DWTHREADID;} process_information; process information structure includes process handle, main thread handle, process ID, main thread ID. The termination process of the process is terminated in the following situations:
Call the EXITPROCESS end process; the main thread of the process returns, implies EXITPROCESS, resulting in the end of the process; the last thread of the process is terminated; calling the TerminateProcess termination process. When you want to end a GDI process, send a WM_QUIT message to the main window, of course, can also call EXITPROCESS from any of its thread.
Win32 thread
Creation of thread
Create a thread using the CreateThread function, the prototype of CreateThread is as follows:
Handle CreateThread
LPSecurity_attributes lpthreadattributes, DWORD DWSTACKSIZE,
LPTHREAD_START_ROUTINE LPSTARTDRESS,
LPVOID LPPARETER,
DWORD dwcreationFlags, // Creation Flags
LPDWORD LPTHREADID
);
among them:
LPTHREADATTRIBUTES indicates that the security property created, is useful under NT.
DWSTACKSIZE Specifies the size of the thread stack, if 0 is the same as the process main thread stack.
LPStartAddress specifies the address that the thread starts running.
LPParameter indicates the 32-bit parameter passed to the thread.
DWCREATEFLAGES indicates whether it is created to hang the thread (value create_suspend), and then call ResumeThread to continue execution.
LPTHREADID is used to store the returned thread ID.
Priority level of thread
Each priority class of the process contains five priority levels. After the priority class identification of the process, the priority level of the thread can be changed. Set the Process Priority class with SetPriorityClass to set the thread priority level with SetThReadpriority.
The NORMAL thread can be preempted by any thread other than the IDE level.
Termination of thread
Terminate a thread:
Call the exitthread function; the thread function returns: the main thread returns to cause the exitProcess to be called, other threads return to cause exitthread being called; call EXITPROCESS to terminate all threads; call TerminateThread Terminate a thread, cause all of them The termination of the thread.
When terminating the process or thread with TerminateProcess or TerminateTHRead, the DLL's portal function Dllmain will not be executed (if there is a DLL).
Thread local storage
If you want each thread to have a static storage data of thread local, a TLS thread is partially stored techniques. TLS assigns a TLS index for the process, and each thread of the process passes the copy of your data variables through this index.
TLS is very useful to DLL. When a new process uses the DLL, use TLSalloc to assign TLS indexes in the DLL entry function dllmain, the TLS index is saved as a process private global variable; after the new thread of the process uses DLL (Attahced to DLL) DLLMAIN assigns dynamic memory and saves the data private data by using TLSSetValue. The DLL function can use TLSGetValue to read private data from the index thread.
The TLS function is as follows:
DWORD TLSALLOC ()
The call is called when the process or DLL is initialized, and the return value (index value) is saved as a global variable.
Bool TlssetValue
DWORD DWTLSINDEX, // TLS INDEX TO SET VALUE for
LPVOID LPTLSVALUE / / VALUE to Be Stored
);
among them:
DWTLSIndex is an index assigned by TLSalloc.
LPTLSVALUE is the data pointer stored in the TLS slot and the pointer points to the data to be saved.
The thread first assigns dynamic memory and saves data into this memory, then call TLSSetValue to save the memory pointer to the TLS slot.
LPVOID TLSGETVALUE
DWORD DWTLSINDEX / / TLS INDEX TO RETRIEVE VALUE FOR
);
Where: DWTLSINDEX is the index of TLSalloc assignment.
When you want to access saved data, use the index to get the data pointer.
Bool tlsfree
DWORD DWTLSINDEX / / TLS INDEX TO FREE
);
among them:
DWTLSIndex is an index assigned by TLSalloc.
When each thread no longer uses local storage data, the thread releases the dynamic memory it assigns. Use the TLSFree release index when the TLS index is no longer required.
Thread Synchronization Synchronization can guarantee that there is only one thread to control a resource (such as the shared resource such as operating system resources) in a time. Shared resources include global variables, public data members or handles. Synchronization can also make the code related to the interaction to execute in a certain order. Win32 provides a set of objects used to implement multi-threaded synchronization. These objects have two states: Signaled or no signals (not signals). Threads use synchronization objects through the synchronous wait function (Wait Functions) provided by Win32 API. A synchronization object is specified when the synchronous wait function is called, and the synchronization function is called blocked until the synchronization object obtains the signal. The blocked thread does not occupy the CPU time.
Synchronous object
Synchronous objects include: critical_section, event (event), MUTEX, Semaphores (semaphore).
Here's how to use these synchronization objects.
Key paragraph object: First, define a critical paragraph object CS: critical_section cs; then, the object is initialized. When initialization, set the object to not_singaled, indicating that the thread is allowed to use resources: InitializecriticalSection (& CS); if a program code needs to synchronize a resource, this is a critical segment code. Call the EntercriticalSECTION function before entering the key segment code, so that other threads cannot perform this code, if they try to perform, it will be blocked. After completing the execution of the key segment, call the LeaveCriticalSECTION function, and other threads can continue to perform this code. If the function is not called, other threads will wait in the endless. Event Object First, call the CreateEvent function to create an event object, which returns an event handle. Then, you can set an event object (a resetEvent), you can also send an event pulse (PLUSEVENT), which set an event object and reset it. There are two forms of reset: automatic reset and manual reset. Specify the reset form when you create an event object. . Automatic reset: After the object gets the signal, release the next available thread (the highest level of thread; if the priority is the same, the first thread in the waiting queue is released). Artificial reset: After the object gets the signal, release all available threads. Finally, using CloseHandle destroyed the created event object. Mutually exclusive object First, call CreateMutex to create a mutex; then call the waiting function, you can use a key resource; finally, call RealSemutex to release the mutually exclusive object. Mutual exclusive objects can be used between processes, but key segment objects can only be used between threads of the same process. The signal amount object is transmitted to 0 when the value of the signal is 0 in Win32. Signals can be used when there are multiple resources that require management. First, call CreateSemaphore Create a semaphore; then call the waiting function, if allowable, use a critical resource; In addition, other handles can be used to synchronize threads: file handles (File Handles)
Name pipe handle (Named Pipe Handels)
Console Input Buff Handles in the console input buffer
Communication Equipment Handle (Communication Device Handles)
Process Handles
Thread Handles
For example, when a process or thread ends, the process or thread handle obtains the signal, waiting for the process or thread ended thread to be released.
Waiting function
Win32 provides a set of waiting functions to allow a thread to block its own execution. Waiting for a function of three categories:
Waiting for a single object: SignalObject WaitforsingleObjectEx Function WaitforsingleObjectEx function parameters include handle and wait time of synchronous objects. Wait for the function to return: Synchronize the object to return when the signal is returned; wait time to return: If the waiting time is not limited (Infinite), only the synchronization object is returned; if the waiting time is 0, then synchronization Returns immediately after the status of the object. Waiting for a plurality of objects (FOR MULTIPLE OBJECTS) such functions include: WaitForMultipleObjects WaitForMultipleObjectsEx MsgWaitForMultipleObjects MsgWaitForMultipleObjectsEx function parameters including synchronization handle to the object, the wait time, or wait a plurality of synchronization objects, etc. Wait for the function to return: one or all synchronization objects return (specified in the parameter waiting for one or more synchronization objects); waiting time reaches: If the waiting time is not limited (Infinite), only synchronization The object obtains the signal returns; if the waiting time is 0, it will return immediately after testing the status of the synchronization object. The function (alterable) function that can be prompted includes:
MsgwaitFormultiPleObjectsex
SignalObjectandWait
WaitFormultiPleObjectsex
WaitforsingleObjectex
These functions are mainly used for overlapped I / O (asynchronous I / O).
The MFC thread processing is based on the Win32 API, and the MFC provides class and functions for processing threads. The class of processing threads is CWINTHREAD, and the function is AFXBEGINTHREAD, AFXENDTHREAD, and more. Table 5-6 explains the member variables and functions of CWINTHREAD. CWINTHREAD is the MFC thread class, which M_Hthread and m_hthreadid are corresponding Win32 thread handles and thread IDs. MFC clearly distinguishes between two threads: User Interface Thread and Worker Threads. User interface threads are generally used to process user inputs and respond to events and messages generated by the user. Worker threads are used to complete tasks that do not require user input, such as time consuming. The Win32 API does not distinguish between the thread type, it only needs to know the start address of the thread so that it starts the thread. The MFC provides the user interface thread specially providing the message pump to handle the user interface. CWINAPP object is an example of a user interface thread object, and CWINAPP derives and handles events and messages generated by class CWINTHREAD.
Create user interface thread
Create a user interface thread by following these steps:
Detect a class with dynamically created capabilities from CwinThread. Using Declare_DyncReate and Implement_DyncReate Macro supports dynamic creation. Overwrite some virtual functions of CWINTHREAD, you can overwrite the function of Table 5-4 About CwinThread. Where the function initInstance must be overwritten, ExitInstance is usually overwritten. Create an MFC thread object and Win32 thread object using AFXBEGINTHREAD. If you don't specify CREATE_SUSPENDED, start the thread when you create a thread. If the creating a thread is specified for create_suspended, the function resumeThread starts the thread in the appropriate place.
Creating a worker thread programmer does not have to derive a new thread class from the CWINTHREAD, just provide a control function, and execute the function after starting. Then, create the MFC thread object and Win32 thread object using AFXBEGINTHREAD. If you don't specify CREATE_SUSPENDED (created after being created), the new thread created begins. If the creating a thread is specified for create_suspended, the function resumeThread starts the thread in the appropriate place. Although the programmer did not derive class from the CWINTHREAD, the MFC provided the default CWINTHREAD object to the worker thread. The AFXBEGINTHREAD user interface thread and worker thread are created by AFXBEGINTHREAD. Now, inspect the function: The MFC provides two overloaded AFXBEGINTHREAD, one for user interface threads, and the other for worker threads, which have the following prototypes and processes, respectively:
AfxBeginThread prototype AfxBeginThread user interface thread of the user interface thread follows: CWinThread * AFXAPI AfxBeginThread (CRuntimeClass * pThreadClass, int nPriority, UINT nStackSize, DWORD dwCreateFlags, LPSECURITY_ATTRIBUTES lpSecurityAttrs) wherein: parameter 1 from CWinThread derived RUNTIME_CLASS classes; parameter 2 specifies Thread priority, if 0, the same as the thread that created the thread; the parameter 3 specifies the stack size of the thread, if 0, the same as the thread that creates the thread; the parameter 4 is a creation ID, if it is create_suspended, Create a thread in a suspension, thread hanging after the thread is created, otherwise the thread starts the execution of the thread after being created. The parameter 5 represents the security attribute of the thread, useful under NT. AfxBeginThread prototype AfxBeginThread worker thread worker thread follows: CWinThread * AFXAPI AfxBeginThread (AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority, UINT nStackSize, DWORD dwCreateFlags, LPSECURITY_ATTRIBUTES lpSecurityAttrs) wherein: an address parameter specifies a control function; parameter specifies 2 Pass the parameters of the control function; parameters 3, 4, 5 specify the priority, stack size, creating identity, security attributes of the thread, and implicitly threading with the user interface. AFXBEGINTHREAD Create thread process
No matter which afxbeginthread, first you create an MFC thread object, then create a Win32 thread object. When creating an MFC thread object, the creation of the user interface thread and the worker thread calls different constructor. The user interface thread is derived from CWINTHREAD, so, first call the default constructor of the derived class, then call the default constructor of CWINTHREAD. The COMMONCONSTRUCT called two constructor in Figure 8-1 is the member function used inside the MFC.
CreateThread and _afxthreadentry MFC create threads using CWINTHREAD :: CreateThread, regardless of worker threads or user interface threads, all specified threads' entry function is _afxthreadentry. _AfXThreadEntry calls the AFXINITTHREAD initialization thread. CreateThread and _afxthreadentry use synchronization means interactively, execute during the creation of threads. CreateTHRead is executed by creating a thread, _afxThreadENTRY is executed by the created thread, both through two event objects (HEVENT and HEVENT2) synchronization: After the new thread is created, create a thread will wait until the HEVENT event is not limited to the new thread gives an creation. As a result; the new thread is in successful or failure, triggering the event hEvent allows the parent thread to run, and waits in Heven2 until the parent thread exits the CreateThread function; the parent thread (creating thread) is waiting, continue, exit CreateTHREAD Triggered HEVENT2 events before the new thread (sub-thread), because the set of HEVENT2 is waiting, start performing the control function (worker thread) or enter the message loop (user interface thread). The MFC uses the following data structure in thread creation: struct _afx_thread_startup {// passed to thread start-up parameters (in) _afx_thread_state * pthreadState; // Parent thread thread state CWINTHREAD * pthread; // Newly created MFC thread object DWORD DWCREATEFLAGS ; // thread creation ID _PNH PFNNEWHANDLER; / / New thread handle handle handle hevent; // synchronous event, thread creation success or failure to set a Handle HEVENT2; / / synchronous event, new thread recovery execution post // Return Give the parameters of the creation thread, assign the value Bool Berror after the new thread resume; // If you create an error, true}; this structure is passed to the _beginthreadex function to create and start the thread. _beginthreadex function is a "C" thread creation function has the following prototype: unsigned long _beginthreadex (void * security, unsigned stack_size, unsigned (__stdcall * start_address) (void *), void * arglist, unsigned initflag, unsigned * thrdaddr); FIG. 8-2 describes the above process. In the figure, _afxThreadentry will create the thread state of this thread and inherit the module status of the parent thread when starting the thread. See Chapter 9 for the MFC status. The end of the thread can be seen from Figure 8-2, and the AFXendThread is used to end the thread that calls it: it will clean up the MFC object created by this thread and the memory space stored allocated, call CWINTHREAD virtual function delete; call "C "The end thread function _endthreadex released resources assigned to threads, but does not turn off the thread handle. CWINTHREAD:: Delete's default implementation is: If the member function m_bdelete of this thread is True, call the "C" operation symbol Delete destroy the MFC thread object itself (DELETE THIS), which will cause the thread object to be called.
If the restructure function detects the thread handle non-air, call CloseHandle to close it. Typically, M_BDelete is True to automatically destroy the thread object, release memory space (MFC memory object allocated in the heap). However, sometimes, after the end of the thread (Win32 thread has no existence), the MFC thread object is useful, and of course the programmer will remember to destroy the thread object. A message loop for implementing a thread is completed by a thread in the MFC. Generally, the MFC default message loop (even with functions cwindthrad :: run),,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,. A thread. Generally there is a form:
While (BDoingbackGroundProcessing)
{
MSG msg;
While (:: PeekMessage (& MSG, NULL, 0, 0, PM_NOREMOVE))
{
IF (! pumpMessage ())
{
BDoingbackgroundProcessing = false;
:: PostquitMessage ();
Break;
}
}
// let MFC Do ITS iDLE Processing
Long lid = 0;
While (AFXGetApp () -> OnIdle (LIDLE ));
// Perform Some Background Processing Here
// using another call to onIdle
}
This interpretation of this section see Fig. 5-3 diagram of the RUN function of the thread.
There are two benefits of the programmer's message loop in the thread, one is to take into account the IDLE process mechanism of the MFC; the other is the event or message generated by the user in a long time.
When waiting for other threads on the synchronous object, you can also use the same way, as long as the condition is
BDoingbackgroundProcessing
Change to the following form:
WaitforsingObject (HHANDLEOFEVENT, 0) == Wait_timeout
I.e.
An important concept is introduced when the MFC handling threads and processes: status, thread state, process state, module status, etc.. Since this concept plays an important role in the MFC, there is more content, so it is specifically described in the next chapter.