Understanding of fork () functions, and understanding of fork Functions
Author:Wang Shanshan, a lecturer at Huaqing vision embedded College.
For those who are new to Unix/Linux operating systems and Write multi-process programs in Linux, fork is one of the most difficult concepts to understand: it returns two values after one execution.
First, let's look at the prototype of the fork function:
# I nclude <sys/types. h>
# I nclude <uniSTd. h>
Pid_t fork (void );
Return Value:
Negative number: if an error occurs, fork () returns-1, and no new process is created. The initial process is still running.
Zero: in the sub-process, fork () returns 0
Positive: In the negative process, fork () returns the PID of the positive sub-process
Next, let's take a look at how to use fork to create sub-processes.
The sample code for creating a sub-process is as follows:
Pid_t child;
If (child = fork () <0)
/* Handle errors */
Else if (child = 0)
/* This is a new process */
Else
/* This is the initial parent process */
The fock function is called twice but returns the ID of the child process to the parent process, and returns 0 to the child process,
This is because the parent process may have many sub-processes, so you must use the returned sub-process ID to track sub-processes,
The child process has only one parent process, and its ID can be obtained through getppid.
The following two examples are compared:
First:
# Include <unistd. h>
# Include <stdio. h>
Int main ()
{
Pid_t pid;
Int count = 0;
Pid = fork ();
Printf ("This is first time, pid = % d \ n", pid );
Printf ("This is secONd time, pid = % d \ n", pid );
Count ++;
Printf ("count = % d \ n", count );
If (pid> 0)
{
Printf ("This is the parent process, the child has the pid: % d \ n", pid );
}
Else if (! Pid)
{
Printf ("This is the child Process. \ n ")
}
Else
{
Printf ("fork failed. \ n ");
}
Printf ("This is third time, pid = % d \ n", pid );
Printf ("This is fouth time, pid = % d \ n", pid );
Return 0;
}
The running result is as follows:
Problem:
This result is strange. Why does the printf statement run twice, but the "count ++;" statement only runs once?
Next, let's see:
# Include <unistd. h>
# Include <stdio. h>
Int main (void)
{
Pid_t pid;
Int count = 0;
Pid = fork ();
Printf ("Now, the pid returned by calling fork () is % d \ n", pid );
If (pid> 0)
{
Printf ("This is the parent procESS, the child has the pid: % d \ n", pid );
Printf ("In the parent process, count = % d \ n", count );
}
Else if (! Pid)
{
Printf ("This is the child process. \ n ");
Printf ("Do your own things here. \ n ");
Count ++;
Printf ("In the child process, count = % d \ n", count );
}
Else
{
Printf ("fork failed. \ n ");
}
Return 0;
}
The running result is as follows:
Now let's explain the question above.
When you look at this program, you must first understand the concept: Before the statement pid = fork (), only one process is executing this code, but after this statement, the two processes are executing. The Code of these two processes is completely the same. The next statement to be executed is if (pid> 0 ).......
In the two processes, the original one is called the "parent process" and the new one is called the "Child process ". The difference between parent and child processes is not only the process ID, but also the variable pid value. The pid stores the fork return value. One of the wonders of fork calling is that it is called only once, but can return twice. It may have three different return values:
1. In the parent process, fork returns the ID of the newly created sub-process;
2. In the sub-process, fork returns 0;
3. If an error occurs, fork returns a negative value;
There are two possible reasons for fork errors: (1) the current number of processes has reached the limit set by the system, and the errno value is set to EAGAIN. (2) If the system memory is insufficient, the errno value is set to ENOMEM.
Next, let's take a look at the description of fork in APUE2:
The new process created by fork is called the child process. this function is called once but returns twice. theonly difference in the returns is that the return value in the child is 0, whereas the return value in the parent is the process ID of the new child. the reason the child's process ID is returned to the parent is that a process can have more than one child, and there is no function that allows a process to o ^ ain the process IDs of its children. the reason fork returns 0 to the child is that a process can have only asingle parent, and the child can always call getppid to o ^ ain the process ID of its parent. (Process ID 0 is reserved for use by the kernel, so it's not possible for 0 to be the process ID of a child .)
A new process created by fork is called a self-process. The fork function is called once, but is returned twice. The only difference in returned values is that 0 is returned in the child process, and the pid of the child process is returned in the parent process. In the parent process, the pid of the child process is returned because the parent process may have more than one child process, and no function can be used by a process to obtain the pid of the child process.
Both the child and the parent continue executing with the instruction that follows the call to fork. the child is a copy of the parent. for example, the child gets a copy of the parent's data space, heap, and stack. note that this is a copy for the child; the parent and the child do not share these portions ofmemory. the parent and the child share the text segment (Section 7.6 ).
Both the child process and the parent process execute the code after the fork function call. The child process is a copy of the parent process. For example, the data space and stack space of the parent process will copy the sub-process, rather than share the memory.
Current implementations don't perform. a complete copy of the parent's data, stack, and heap, since a fork is often followed by an exec. instead, a technique called copy-on-write (COW) is used. these regions are shared by the parent and the child and have their protection changed by the kernel to read-only. if either process tries to modify these regions, the kernel then makes a copy of that piece of memory only, typically a "page" in a virtual memorysystem. section 9.2 of Bach [1986] and Sections 5.6 and 5.7 of McKusick et al. [2, 1996] provide more detail on this feature.
Let's give a detailed comment.
# Include <unistd. h>
# Include <stdio. h>
Int main (void)
{
Pid_t pid;
Int count = 0;
/* Execute the fork call and create a new process, which shares the data and stack space of the parent process. The subsequent Code commands create a copy for the child process. A fock call is a replication process. Unlike a thread, a function is provided as an entry. After a fock call, the entry of a new process is located in the Next statement of the fock. */
Pid = fork ();
/* The pid value here indicates whether the fork is currently executing the parent process or child process */
Printf ("Now, the pid returned by calling fork () is % d \ n", pid );
If (pid> 0)
{
/* When fork is returned in the child process, the fork call returns the pid of the child process to the parent process. If the code is executed, but note that the count value is still 0, because the count value in the parent process is never re-assigned, we can see that the data and stack space of the child process are independent of the parent process, rather than sharing data */
Printf ("This is the parent process, the child has the pid: % d \ n", pid );
Printf ("In the parent process, count = % d \ n", count );
}
Else if (! Pid)
{/* Perform the auto-increment operation on count in the sub-process, but the count value in the parent process is not affected. The count value in the parent process is still 0 */
Printf ("This is the child process. \ n ");
Printf ("Do your own things here. \ n ");
Count ++;
Printf ("In the child process, count = % d \ n", count );
}
Else
{
Printf ("fork failed. \ n ");
}
Return 0;
}
That is to say, the next process in Linux has three parts of data in the memory: "code segment", "Stack segment", and "data segment ". "Code segment", as its name implies, stores the data of program code. If several processes on the machine run the same program, they can use the same code segment. The "Stack segment" stores the return address of the subroutine, the parameters of the subroutine, and the local variables of the program. The data segment stores the global variables, constants, and dynamic data space allocated by the Program (for example, space obtained using functions such as malloc ). If the system runs several identical programs at the same time, the same stack segment and data segment cannot be used between them.
After careful analysis, we can know:
Once a program calls the fork function, the system prepares the preceding three segments for a new process. First, the system allows the new process and the old process to use the same code segment, because their programs are the same, the system copies a copy of the data segment and stack segment to the new process. In this way, all data of the parent process can be left to the child process. However, once a child process starts running, it inherits all the data of the parent process, but in fact the data has been separated and there is no impact between them, that is, they no longer share any data.
Fork () not only creates child processes with the same code as the parent process, but also automatically copies all context scenarios of the parent process at the fork execution point to the child process, including:
-- Global and local variables
-- Open file handle
-- Shared memory, messages, and other synchronization objects
If the two processes want to share any data, they need to use another function (shmget, shmat, shmdt, and so on. Now there are two processes. For the parent process, the fork function returns the process Number of the subroutine, and for the subroutine, the fork function returns zero. In this way, for the program, as long as you determine the return value of the fork function, you will know whether you are in the parent process or child process.
"This article is written by Hua Qing vision http://www.embedu.org/index.htm"