I. Introduction to fork
A process, including code, data, and resources allocated to the process. The fork () function creates a process that is almost identical to the original process through system calls, that is, the two processes can do exactly the same thing, but if the initial parameters or input variables are different, the two processes can also do different things.
After a process calls the fork () function, the system allocates resources for new processes, such as space for storing data and code. Then, copy all values of the original process to the new process. Only a few values are different from those of the original process. It is equivalent to cloning a self.
Let's look at an example:
# Include <unistd. h>
# Include <stdio. h>
Int main ()
{
Pid_tfpid; // fpid indicates the value returned by the fork function.
Intcount = 0;
Fpid = fork ();
If (fpid <0)
Printf ("errorin fork! ");
Elseif (fpid = 0 ){
Printf ("Iam the child process, my process ID is % d \ n", getpid ());
Printf ("I am Dad's son \ n"); // Chinese looks more straightforward for some people.
Count ++;
}
Else {
Printf ("Iam the parent process, my process ID is % d \ n", getpid ());
Printf ("I am a child, his father \ n ");
Count ++;
}
Printf ("statistical result: % d \ n", count );
Return0;
}
The running result is:
Iam the child process, my process ID is 5574
I'm Dad's son.
The statistical result is: 1
Iam the parent process, my process ID is 5573
I'm a child, his father.
The statistical result is: 1
Before the statement fpid = fork (), only one process is executing this code, but after this statement, the two processes are executed, and the two processes are almost identical, the next statement to be executed is if (fpid <0 )......
Why are the fpids of the two processes different? This is related to the features of the fork function.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 process 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;
After the fork function is executed, if the new process is successfully created, two processes will appear,One is a sub-process and the other is a parent process.. In the child process, the fork function returns 0, and in the parent process, fork returns the ID of the new Child process. We canDetermine whether the current process is a child process or a parent process based on the value returned by fork..
Reference a netizen to explain why the fpid value is different in the parent-child process. "In fact, it is equivalent to a linked list. The process forms a linked list. The fpid (P means point) of the parent process points to the process ID of the child process. Because the child process does not have a child process, its fpid is 0.
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.
After the new process is successfully created, two processes are basically the same in the system. The execution of these two processes is not in a fixed sequence. Which process is executed first depends on the system's process scheduling policy.
Each process has a unique (different)Process ID. You can use getpid ()Function acquisition, there isThe variable that records the PID of the parent process. You can use getppid ()Function to obtain the value of the variable.
After the fork is executed, two processes appear,
Some people say that the content of the two processes is exactly the same. How can we print different results? That is because of the condition judgment. The above lists only the code and commands of the process, as well as variables.
After fork is executed, the variable of process 1 is Count = 0, fpid! = 0 (parent process ). The variables of process 2 are COUNT = 0 and fpid = 0 (sub-process). The variables of these two processes are independent and are not shared in different addresses. We can say that we use fpid to identify and operate parent-child processes.
Some may wonder why the code is not copied from # include, because fork copies the current situation of the process. When fork is executed, the process has been executed int COUNT = 0; fork only copies the code to be executed to the new process.
Ii. Advanced fork knowledge
First read the code:
07. # include <unistd. h>
08. # include <stdio. h>
09. Int main (void)
10 .{
11. Int I = 0;
12. printf ("I son/PA ppid PID fpid \ n ");
13. // ppid indicates the PID of the parent process of the current process.
14. // PID indicates the PID of the current process,
15. // fpid indicates the value that fork returns to the current process.
16. For (I = 0; I <2; I ++ ){
17. pid_t fpid = fork ();
18. If (fpid = 0)
19. printf ("% d child % 4D % 4D % 4D \ n", I, getppid (), getpid (), fpid );
20. Else
21. printf ("% d parent % 4D % 4D % 4D \ n", I, getppid (), getpid (), fpid );
22 .}
23. Return 0;
24 .}
The running result is:
ISON/PA ppid PID fpid
0 parent 2043 3224 3225
0 child 3224 3225 0
1 parent 2043 3224 3226
1 parent 3224 3225 3227
1 child 1 3227 0
1 child 1 3226 0
This code is interesting. Let's analyze it carefully:
Step 1: In the parent process, the command is executed in the for loop, I = 0, and then fork is executed. After fork is executed, two processes appear in the system, p3224 and p3225 respectively (I used pxxxx to indicate that the process ID is XXXX ). We can see that the parent process of the parent process p3224 is p2043, and the parent process of the child process p3225 is p3224. We use a linked list to represent this relationship:
P2043-> p3224-> p3225
After fork for the first time, the variable p3224 (parent process) is I = 0, fpid = 3225 (the fork function returns to the child process ID in the parent process), and the Code content is:
View plaincopy to clipboardprint?
01. For (I = 0; I <2; I ++ ){
02. pid_t fpid = fork (); // execution completed, I = 0, fpid = 3225
03. If (fpid = 0)
04. printf ("% d child % 4D % 4D % 4D \ n", I, getppid (), getpid (), fpid );
05. Else
06. printf ("% d parent % 4D % 4D % 4D \ n", I, getppid (), getpid (), fpid );
07 .}
08. Return 0;
For (I = 0; I <2; I ++ ){
Pid_t fpid = fork (); // execution completed, I = 0, fpid = 3225
If (fpid = 0)
Printf ("% d child % 4D % 4D % 4D \ n", I, getppid (), getpid (), fpid );
Else
Printf ("% d parent % 4D % 4D % 4D \ n", I, getppid (), getpid (), fpid );
}
Return 0;
The variables of p3225 (sub-process) are I = 0, fpid = 0 (the fork function returns 0 in the sub-process), and the Code content is:
View plaincopy to clipboardprint?
01. For (I = 0; I <2; I ++ ){
02. pid_t fpid = fork (); // execution completed, I = 0, fpid = 0
03. If (fpid = 0)
04. printf ("% d child % 4D % 4D % 4D \ n", I, getppid (), getpid (), fpid );
05. Else
06. printf ("% d parent % 4D % 4D % 4D \ n", I, getppid (), getpid (), fpid );
07 .}
08. Return 0;
For (I = 0; I <2; I ++ ){
Pid_t fpid = fork (); // execution completed, I = 0, fpid = 0
If (fpid = 0)
Printf ("% d child % 4D % 4D % 4D \ n", I, getppid (), getpid (), fpid );
Else
Printf ("% d parent % 4D % 4D % 4D \ n", I, getppid (), getpid (), fpid );
}
Return 0;
So print the result:
0 parent 2043 3224 3225
0 child 3224 3225 0
Step 2: assume that the parent process p3224 is executed first. When the next cycle is entered, I = 1, and then fork is executed. Another process p3226 is added to the system. For the parent process at this time, p2043-> p3224 (current process)-> p3226 (created sub-process ).
For the sub-process p3225, after the first loop is executed, I = 1, and then fork is executed. A new process p3227 is added in the system. For this process, p3224-> p3225 (current process) -> p3227 (the created sub-process ). From the output, we can see that p3225 is a child process of p3224 and is now the parent process of p3227. Parent and Child are relative, which should be easy to understand. As long as the current process executes fork, the process becomes the parent process and the parent is printed.
Therefore, the output is as follows:
1 parent 2043 3224 3226
1 parent 3224 3225 3227
Step 3: create two processes p3226 and p3227 in step 2. The two processes are finished after the printf function is executed, because the two processes cannot enter the third loop and fork, return 0 is executed, and so are other processes.
The following figure shows the output of p3226 and p3227:
1 child 1 3227 0
1 child 1 3226 0
Careful readers may notice that the parent processes of p3226 and p3227 should not be p3224 and p3225. How can they be 1? Here we have to talk about the process of Process Creation and death. After executing the second loop in p3224 and p3225, the main function should exit, that is, the process should die, because it has done everything. After p3224 and p3225 die, p3226 and p3227 will have no parent process, which is not allowed in the operating system, so the parent process of p3226 and p3227 will be set to P1, p1 will never die. As for why, I will not introduce it here. I will leave it to "3. Fork high-level knowledge.
To sum up, the procedure is as follows:
This program eventually generates three sub-processes and executes the printf () function six times.
Let's take a look at the Code:
# Include <unistd. h>
# Include <stdio. h>
Int main (void)
{
Int I = 0;
For (I = 0; I <3; I ++ ){
Pid_t fpid = fork ();
If (fpid = 0)
Printf ("son \ n ");
Else
Printf ("Father \ n ");
}
Return 0;
}
The execution result is:
Father
Son
Father
Father
Father
Father
Son
Son
Father
Son
Son
Son
Father
Son
I will not explain it in detail here. I will only make a rough analysis.
For I = 0 1 2
Father
Son
Son father
Son
Son Father
Son
Son father
Son
Each line indicates the running result of a process.
To sum up the rule, the number of times the printf function is executed for N cycles is 2*(1 + 2 + 4 + ...... + 2n) times. The number of created sub-processes is 1 + 2 + 4 + ...... + 2N.
Some people on the Internet say that N cycles produce 2*(1 + 2 + 4 + ...... + 2n) processes. This statement is incorrect. I hope you will pay attention to it.
At the same time, if you want to test whether several sub-processes have been created in the next program, the best way is to call the printf function to print the PID of the process, that is, call printf ("% d \ n", getpid (); or use printf ("+ \ n"); to determine which processes are generated. It is inappropriate for someone to call printf ("+"); To count several processes created. Let me analyze the specific cause.
Old Rules: Let's look at the following code:
# Include <unistd. h>
# Include <stdio. h>
Int main (){
Pid_tfpid; // fpid indicates the value returned by the fork function.
// Printf ("fork! ");
Printf ("fork! \ N ");
Fpid = fork ();
If (fpid <0)
Printf ("errorin fork! ");
Elseif (fpid = 0)
Printf ("Iam the child process, my process ID is % d \ n", getpid ());
Else
Printf ("Iam the parent process, my process ID is % d \ n", getpid ());
Return0;
}
The execution result is as follows:
Fork!
Iam the parent process, my process ID is 3361
Iam the child process, my process ID is 3362
If the printf ("fork! \ N "); comment out and execute printf (" fork! ");
The execution result of the new program is:
Fork! I am the parent process, my process ID is 3298
Fork! I am the child process, my process ID is 3299
The only difference between a program is that\ N carriage return, why is the result so different??
This is related to the buffer mechanism of printf. In some content of printf, the operating system only places the content in the Buffer Queue of stdout and does not actually write it to the screen. However, as long as \ n is displayed, stdout will be refreshed immediately, so it can be printed immediately.
Printf ("fork! ")," Fork !" It is only put in the buffer. When the program runs to fork, the buffer "fork !" The quilt process has been copied. Therefore, fork is also available in the stdout buffer !. So what you finally see is fork! It was printf twice !!!!
And run printf ("fork! \ N ")," fork !" Immediately printed to the screen. Fork is not included in the stdout buffer in the child process to which the fork is sent! Content. So the result you see is fork! Printf once !!!!
Therefore, printf ("+"); cannot correctly reflect the number of processes.
You may feel a little tired after reading so much, but I have to post the last code to further analyze the fork function.
# Include <stdio. h>
# Include <unistd. h>
Int main (INT argc, char * argv [])
{
Fork ();
Fork () & fork () | fork ();
Fork ();
Return 0;
}
The problem is that the process itself is not counted as the number of processes created by the program.
To answer this question, let's first verify the number of processes here.
# Include <stdio. h>
Int main (INT argc, char * argv [])
{
Fork ();
Fork () & fork () | fork ();
Fork ();
Printf ("+ \ n ");
}
The answer is a total of 20 processes. Except for the main process, there are 19 other processes.
Let's take a closer look at why there are 19 other processes.
The first fork and the last fork will certainly be executed.
You can draw a picture to describe the three forks in the middle.
Pay attention to the & and | operators.
A & B. If a = 0, it is unnecessary to continue executing & B; if A is not 0, it is necessary to continue executing & B.
A | B. If a is not 0, it is unnecessary to continue | B, and a = 0, it is necessary to continue | B.
Fork () has different return values for the parent process and child process. Based on the preceding graph of A & B and A | B, five branches can be drawn.
In addition to the previous fork and the final fork, a total of 4*5 = 20 processes, except the main process, 19 processes.
Iii. Fork high-level knowledge
In this section, I will mainly talk about the creation, death, and scheduling of operating system processes in the fork function. Due to time and energy restrictions, I will write it here first. Next time I will find a time to complete the remaining content.
References:
Http://blog.csdn.net/dog_in_yellow/archive/2008/01/13/2041079.aspx
Http://blog.chinaunix.net/u1/53053/showart_425189.html
Http://blog.csdn.net/saturnbj/archive/2009/06/19/4282639.aspx
Http://www.cppblog.com/zhangxu/archive/2007/12/02/37640.html
Http://www.qqread.com/linux/2010/03/y491043.html
Http://www.yuanma.org/data/2009/1103/article_3998.htm