Process and multi-process management in VC ++

Source: Internet
Author: User
Process and multi-process management methods in VC ++-general Linux technology-Linux programming and kernel information. For details, refer to the following section. A process is an instance of a running application loaded to the memory in the current operating system. Each process is composed of a kernel object and an address space. The kernel object allows the system to store statistics about the process and enables the system to manage the process, the address space includes the code and data of all program modules, as well as dynamic allocated space such as the thread stack and heap allocation space. A process only exists and cannot perform any operation on its own. It must have at least one thread running in its environment and be responsible for executing the code in the process address space. A thread is started at the same time as the process starts. This thread is called the main thread or the execution thread, so that the thread can continue to create sub-threads. If the main thread exits, there is no possibility of a process. The system will automatically undo the process and release its address space.

The image of each executable file or dynamic link library file loaded into the process address space is assigned a globally unique instance handle (Hinstance) associated with it ). The instance handle is actually a basic memory address that records the location where the process is loaded. The instance handle of the process is passed through the first HINSTANCE hinstExe parameter in the program entry function WinMain (). The actual value is the address of the basic address space used by the process. For programs linked by VC ++, the default basic address space is 0x00400000. Do not change this value unless necessary. In the program, you can use the GetModuleHandle () function to obtain the basic address space used by the specified module.
Create a sub-process

Process Creation is implemented through the CreateProcess () function. CreateProcess () starts and runs a new program by creating a new process and the main thread running in its address space. Specifically, when executing the CreateProcess () function, the operating system is responsible for creating a process kernel object, the initialization count is 1, and immediately creates a virtual address space for the new process. Then load the code and data of the executable file or any other necessary dynamic link library file into the address space. When creating the main thread, the system is also responsible for creating a thread Kernel Object and initializing it to 1. Finally, start the main thread and execute the entry function WinMain () of the process to create the process and execution thread.

The prototype Declaration of the CreateProcess () function is as follows:

BOOL CreateProcess (
Lptstr lpApplicationName, // executable module name
LPTSTR lpCommandLine, // command line string
LPSECURITY_ATTRIBUTES lpProcessAttributes, // process security attributes
LPSECURITY_ATTRIBUTES lpThreadAttributes, // Security Attribute of the thread
BOOL bInheritHandles, // handle inheritance flag
DWORD dwCreationFlags, // create a flag
LPVOID lpEnvironment, // pointer to the new environment Block
Maid directory, // pointer to the current directory name
LPSTARTUPINFO lpStartupInfo, // pointer to the startup information structure
LPPROCESS_INFORMATION lpProcessInformation // pointer to the Process Information Structure
);

During program design, a specific function module can be implemented in different forms, such as functions or threads. For the same process, these functions and threads exist in the same address space, and most of them only process data related to them during execution. If an algorithm has an error, it may damage other important content in the same address space, which may cause serious consequences. To protect the content in the address space, you can consider placing the operations that require access to the data in the address space of another process into the address space of another process, and only allow access to the data in the original process address space. Specifically, you can create a sub-process through the CreateProcess () function in the process. The sub-process only accesses the relevant data in the parent process address space during all the processes, this protects all data in the address space of the parent process that is not related to the current sub-process execution task. In this case, the sub-process is similar to the function and thread. It can be seen as a process in which the parent process is running. Therefore, the parent process is required to master the startup, execution, and exit of the child process. The following code shows the process:

// Temporary Variable
CString sCommandLine;
Char cWindowsDirectory [MAX_PATH];
Char cCommandLine [MAX_PATH];
DWORD dwExitCode;
PROCESS_INFORMATION pi;
STARTUPINFO si = {sizeof (si )};
// Obtain the Windows directory
GetWindowsDirectory (cWindowsDirectory, MAX_PATH );
// Start the command line of the "Notepad" program
SCommandLine = CString (cWindowsDirectory) + "\ NotePad.exe ";
: Strcpy (cCommandLine, sCommandLine );
// Start notepad as a sub-process
BOOL ret = CreateProcess (NULL, cCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, & si, π );
If (ret ){
// Close the main thread handle of the sub-process
CloseHandle (pi. hThread );
// Wait for the sub-process to exit
WaitForSingleObject (pi. hProcess, INFINITE );
// Obtain the exit code of the sub-process
GetExitCodeProcess (pi. hProcess, & dwExitCode );
// Close the sub-Process Handle
CloseHandle (pi. hProcess );
}

This code first uses CreateProcess () to create a "Notepad" program for Windows as a sub-process. After the sub-process is started, the parent process waits for its execution to end through the WaitForSingleObject () function, the parent process is always blocked when the child process does not exit. The role of the child process is similar to the function in a single thread. Once the sub-process exits, the pi that the WaitForSingleObject () function waits. the hProcess object will be notified that the parent process will continue. If necessary, you can use GetExitCodeProcess () to obtain the exit code of the child process.

In comparison, the parent process does not exchange or communicate with the child process after the child process is started, whether or not the sub-process created by the sub-process is successfully executed is irrelevant to the parent process. Many large softwares also adopt this kind of idea in their design and implement some functions completely through independent applications, to execute an operation, you only need to start the corresponding sub-process through the main program. The specific processing work is done by the sub-process. This type of sub-process creation process is simpler. For example, for the above Code, you only need to remove the sub-process handle pi. hProcess wait:

BOOL ret = CreateProcess (NULL, cCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, & si, π );
If (ret ){
// Close the main thread handle of the sub-process
CloseHandle (pi. hThread );
// Close the sub-Process Handle
CloseHandle (pi. hProcess );
}

You can use the dwCreationFlags parameter to set the priority of a sub-process when creating a process. The preceding sample code uses the default priority when creating a sub-process. To set the priority to a high value, you can modify it as follows:

BOOL ret = CreateProcess (NULL, cCommandLine, NULL, NULL, FALSE, HIGH_PRIORITY_CLASS, NULL, NULL, & si, π );

If no special priority is set during process creation, you can use the SetPriorityClass () function to dynamically set the priority. This function requires the handle and priority identifier of the process to be operated as the entry parameter. The function is prototype:

BOOL SetPriorityClass (HANDLE hProcess, DWORD dwPriorityClass );

For example code with no priority set, the parent process can dynamically change its priority setting after the child process starts:

SetPriorityClass (pi. hProcess, HIGH_PRIORITY_CLASS );

Or the priority setting is changed by the sub-process after it is started. Note that the Process Handle should be set as the sub-process handle, which can be obtained through the GetCurrentProcess () function:

HANDLE hProcess = GetCurrentProcess ();
SetPriorityClass (hProcess, HIGH_PRIORITY_CLASS );

Mutex operation of processes

Under normal circumstances, the running of a process generally does not affect other running processes. However, programs with special requirements, such as using a serial port in an exclusively-owned manner, require that other programs that attempt to use the port device do not run during the process, in addition, such programs generally do not allow multiple instances to run the same program. This leads to the process mutex problem.

The core idea of implementing process mutex is relatively simple: when a process is started, first check whether the current system already has an instance of this process. If not, the process will successfully create and set the tag that identifies the existing instance. Then, when you create a process, you will be aware that its instance already exists through this tag, so that the process can only have one instance in the system. You can use multiple methods, such as memory ing files, the number of famous events, the number of famous mutex, and global shared variables. The following describes two representative methods:

// Create mutex
HANDLE m_hMutex = CreateMutex (NULL, FALSE, "Sample07 ");
// Check the error code
If (GetLastError () = ERROR_ALREADY_EXISTS ){
// If a mutex exists, release the handle and reset the mutex.
CloseHandle (m_hMutex );
M_hMutex = NULL;
// Exit the program
Return FALSE;
}

The above Code demonstrates the usage of the famous mutex in process mutex. The core of the Code is the creation of the famous mutex by CreateMutex. The CreateMutex () function can be used to create a famous or unknown mutex object. Its prototype is:

HANDLE CreateMutex (
LPSECURITY_ATTRIBUTES lpMutexAttributes, // pointer to the Security Attribute
BOOL bInitialOwner, // initialize the owner of the mutex object
Lptstr lpName // pointer to the mutex object name
);

If the function is successfully executed, a handle of the mutex object is returned. If a mutex with the same name already exists before CreateMutex () is executed, the function returns the handle with the same mutex and obtains the error code ERROR_ALREADY_EXIST through GetLastError. It can be seen that through the detection of the error code ERROR_ALREADY_EXIST, CreateMutex () can be mutually exclusive to the process.

The method of using global shared variables is mainly implemented in the MFC framework program through the compiler. Create a new section using the # pragma data_seg pre-compiled command. A variable can be defined by the volatile keyword in this section and must be initialized. The Volatile keyword specifies that variables can be accessed by external processes. Finally, to enable the variable to play a role in the process of mutual exclusion, you must set it as a shared variable and allow read and write access permissions. This can be notified to the compiler through the # pragma comment pre-compilation command. The following provides a list of mutually exclusive code for processes that use global variables:

# Pragma data_seg ("Shared ")
Int volatile g_lAppInstance = 0;
# Pragma data_seg ()
# Pragma comment (linker, "/section: Shared, RWS ")
......
If (++ g_lAppInstance> 1)
Return FALSE;

This code segment is used to add 1 to the global shared variable g_nAppInstancd when the process starts. If the value is found to be greater than 1, FALSE is returned to notify the process to end. It should be pointed out that in order to make the above two segments of code truly play a mutually exclusive role to the process, they must be placed in the entry code of the application, that is, the start of the InitInstance () function of the initialization instance of the application class.

End Process

A process only provides an address space and a kernel object. Its running is reflected by the main thread in its address space. When the entry point function of the main thread returns, the process ends. The termination method of this process is the normal exit of the process, and all the thread Resources in the process can be cleared correctly. In addition to the normal launch method of this process, it is sometimes necessary to force the execution of this process or other processes in the program through code. The ExitProcess () function can be used in a thread in the process, and the operation of the process will be terminated immediately. The prototype of the ExitProcess () function is:

VOID ExitProcess (UINT uExitCode );

The uExitCode parameter sets the exit code for the process. This function is mandatory. After the execution is complete, the process has been terminated. Therefore, no code located after it can be executed. Although the ExitProcess () function can notify the dynamic link library associated with the process at the end of the process, the execution of this function is mandatory, so that ExitProcess () functions have security risks. For example, if you have applied for a period of memory with the new operator before the program calls the ExitProcess () function, the ExitProcess () function cannot be released through the delete operator because of its mandatory nature, this causes memory leakage. Note that ExitProcess () functions are mandatory and insecure.

ExitProcess () can only force the exit of this process. If you want to force the termination of other processes in a process, use TerminateProcess. Unlike ExitProcess (), after the TerminateProcess () function is executed, the terminated process will not receive any notification about program exit. That is to say, the terminated process cannot finish the work before exiting before the end of the operation. Therefore, TerminateProcess () is usually used to force the process to end only when no other method can force the process to exit. The following is a prototype of the TerminateProcess () function:

BOOL TerminateProcess (HANDLE hProcess, UINT uExitCode );


The hProcess and uExitCode parameters are process handles and exit codes respectively. If the process ends, you can get the handle through GetCurrentProcess. TerminateProcess () is executed asynchronously. After a call is returned, you cannot determine whether the terminated process has actually exited. If the process that calls TerminateProcess () cares about this details, you can use WaitForSingleObject () to wait for the real end of the process.

Summary

Multi-process is an important part of multi-task management. The above section describes the basic concepts and main technologies of multi-process management, such as the creation and termination of sub-processes and the mutex operation between processes. Through this article, readers should be able to have a preliminary understanding of multi-process management.
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.