In Unix systems, the only way to create a new process is to call the fork system. The process called fork is called the parent process, and the newly created process is called the child process. Syntax format of system call:
PID = fork ();
When the fork is returned from the system call, the two processes have the same user-level context except the PID of the returned value. In the sub-process, the PID value is zero. The process 0 created by the core internal and external locations at system startup is the only process created without the system call fork.
The core is to call fork to complete the following operations:
- Assign an empty entry to the new process in the progress table.
- Assign a unique process ID (PID) to the sub-process ).
- Make a logical copy of the context of the parent process. Some parts of a process, such as the body area, may be shared by several processes. Therefore, the core sometimes only needs to increase the number of references in a specific area, instead of copying the region to a new physical memory zone.
- Increase the number of file tables and index node tables associated with the process.
- Returns the process number of the child process to the parent process, and returns zero to the child process.
It is very important to understand the implementation of the System Call fork, because the sub-process starts its execution sequence as it drops from the sky.
The following is the fork algorithm called by the system. The core is confident that there are enough resources to successfully complete the fork. If the resource does not meet the requirements, the system fails to call fork. If the resource meets the requirements, the core finds an empty entry in the Process Table and starts to construct the context of the sub-process.
Algorithm: fork
Input: None
Output: PID of the parent process as a child process
The sub-process is 0.
{
Check available core resources
Take an idle table entry and a unique PID Number.
Check that the user does not run too many processes
Set the sub-process status to "CREATE ".
Copy the data in the parent process's table to the child table.
Index node of the current directory and reference of the changed root directory (if possible) plus 1
Add 1 to the reference number of open files in the file table
Copy the context of the parent process in the memory
In the system-level context of a sub-process, medium pressure is applied to the virtual system-level context layer.
/* The virtual context layer contains sub-Processes
* Identify your own data and schedule sub-Processes
* Start from here
*/
If (the process being executed is a parent process ){
Set the sub-process status to "ready ".
Return (pid of the sub-process) // from the system to the user
}
Else {
Initialize the timing Zone
Return 0;
}
}
Let's take a look at the example below. This program indicates the shared access to files after fork is called by the system. When a user calls this program, there should be two parameters: one is the existing file name and the other is the new file name to be created. This process opens an existing file, creates a new file, and then, if there is no error, it calls fork to create a child process. Sub-processes can inherit the files of the parent process by using the same file descriptor (that is, files opened and created by the parent process ).
Of course, the parent process and child process must independently call the rdwrt function and execute a loop, that is, read a byte from the source file and write a byte to the target file. When the system calls read to the end of a file, rdwrt returns immediately.
# Include <fcntl. h>
Int fdrd, fdwt;
Char C;
Main (INT argc, char * argv [])
{
If (argc! = 3 ){
Exit (1 );
}
If (fdrd = open (argv [1], o_rdonly) =-1 ){
Exit (1 );
}
If (fdwt = creat (argv [2], 0666) =-1 ){
Exit (1 );
}
Fork ();
// The two processes run the same code
Rdwrt ();
Exit (0 );
}
Rdwrt ()
{
For (;;){
If (read (fdrd, & C, 1 )! = 1 ){
Return;
}
Write (fdwt, & C, 1 );
}
}
In this example, the file descriptors of both processes point to the same file table item. These two processes will never read or write to the same file offset, because the core will increase the file offset after each read and write call. Although the two processes seem to have copied the source files twice, the content of the target file depends on the order of the two processes scheduled by the core because they share the task. If the core schedules two processes in this way: enable them to execute their system calls alternately, or even enable them to execute each pair of Read and Write calls alternately, the content of the target file is exactly the same as that of the source file. But consider this situation: the two processes are about to read two consecutive characters in the source file "AB ". Assume that the parent process reads the character "A". At this time, the core performs context switching before the parent process writes to execute the child process. If a child process reads the character "B" and writes it to the target file before the parent process is scheduled, the target file will no longer contain the string "AB ", it contains "ba. The core does not guarantee the relative speed of process execution.
Let's take a look at another example:
# Include <string. h>
Char string [] = "Hello, world ";
Main ()
{
Int count, I;
Int to_par [2], to_chil [2]; // pipeline to parent and child Processes
Char Buf [256];
Pipe (to_par );
Pipe (to_chil );
If (Fork () = 0 ){
// The sub-process is executed here
Close (0); // close the old standard input.
DUP (to_child [0]); // copy the read of the MPs queue to the standard input.
Close (1); // close the old standard output
DUP (to_par [1]); // copy the write of the pipeline to the standard output
Close (to_par [1]); // close unnecessary pipeline Descriptors
Close (to_chil [0]);
Close (to_par [0]);
Close (to_chil [1]);
For (;;){
If (COUNT = read (0, Buf, sizeof (BUF) = 0)
Exit ();
Write (1, Buf, count );
}
}
// The parent process is executed here
Close (1); // reset the Standard Input and Output
DUP (to_chil [1]);
Close (0 );
DUP (to_par [0]);
Close (to_chil [1]);
Close (to_par [0]);
Close (to_chil [0]);
Close (to_par [1]);
For (I = 0; I <15; I ++ ){
Write (1, String, strlen (string ));
Read (0, Buf, sizeof (BUF ));
}
}
The child process inherits the file descriptors 0 and 1 (standard input and standard output) from the parent process ). The two execution system calls pipe are assigned two file descriptors in the array to_par and to_chil respectively. Then the process executes the system to call fork and copies the process context: like in the previous example, each process accesses its own private data. The parent process closes its standard output file (file descriptor 1) and copies the write file descriptor (DUP) returned by to_chil from the MPs queue. Because the first empty slot in the file descriptor table of the parent process was just removed from the shutdown, the core copies the file descriptor written by the pipeline to the first item in the file descriptor table. In this way, the standard output file descriptor is the write file descriptor of the MPs queue to_chil. The parent process replaces the standard input file descriptor with the read file descriptor of the MPs queue to_par with a similar operation. Similarly, a sub-process closes its standard input file (file descriptor 0) and copies the read file descriptor of the (DUP) pipe line to_chil. Because the first null entry in the file descriptor table is the original standard input item, the standard input of the sub-process is the read file descriptor of the to_chil pipeline. A child process performs a similar operation to convert its standard output to the write file descriptor of the to_par of the MPs queue. Then the two processes close the file descriptor returned from pipe. The result of the above operation is: when the parent process outputs something to the standard, it actually writes data to to_chil -- to the child process, the sub-process reads the pipeline line from its standard input. When a child process writes data to its standard output, it actually writes data to to_par-to the parent process, and the parent process receives data from the MPs queue line from its standard input. Two processes exchange messages through two pipelines.
Regardless of the execution sequence of the two processes, the execution results of this program remain unchanged. They may sleep and wake up to wait for each other. The parent process exits after 15 cycles. Then, the sub-process reads the "End of file" Mark and exits because the process is not written to the MPs queue.
Http://docs.huihoo.com/gnu/linux/fork.html)
Understanding of fork FunctionsProcess Creation (http://blog.csdn.net/binghuiliang/archive/2007/10/22/1836710.aspx)
It is easy to create a system call for a process. You only need to call the fork function.
# Include <unistd. h>
Pid_t fork ();
After a process calls fork, the system creates a sub-process. This sub-process is different from the parent process only by its process ID and parent process ID. Others are the same. Just like clone itself. Of course it makes no sense to create two identical processes. To distinguish Parent and Child processes, we must track the return values of fork. When the fork fails to be used (the memory is insufficient or the maximum number of processes has reached), fork returns-1. Otherwise, the return value of fork plays an important role. For the parent process fork, the ID of the child process is returned, and for the child process, fork returns 0. The Parent and Child processes are differentiated based on the returned values. Why should a parent process create a child process? As we have mentioned earlier, Linux is a multi-user operating system. At the same time, many users compete for system resources. Sometimes a process creates a sub-process to compete for resources to complete the task earlier. Once a child process is created, the Parent and Child processes run from the fork together to compete for system resources. Sometimes we want the child process to continue execution, and the parent process is blocked until the child process completes the task. In this case, we can call the wait or waitpid system.
Fork Function Learning :(Http://blog.csdn.net/saturnbj/archive/2009/06/19/4282639.aspx)
# Include <sys/types. h>
# Include <unistd. h>
# Include <stdio. h>
# Include <stdlib. h>
Main ()
{
Pid_t PID; pid = fork ();
If (PID <0)
Printf ("error in fork! ");
Else if (pid = 0)
Printf ("I am the child process, my process ID is % DN", getpid ());
Else
Printf ("I am the parent process, my process ID is % DN", getpid ());
}
This Code describes how to use the fork function to create sub-processes. The Parent and Child processes run simultaneously and generate different running results. The running result is as follows:
#./A. Out
I am the child process, my process ID is 4286
I am the parent process, my process ID is 4285
Fork is the meaning of fork in English. In fork, take the meaning behind it. The fork function creates a sub-process. The sub-process and the parent process start to run the program after the split at the same time (in fact, it is a CPU time-sharing process.
Rewrite the program:
Main ()
{
Pid_t PID;
Printf ("/n [% d] Not fork pid = % d/N", getpid (), pid );
PID = fork ();
Printf ("/n [% d] forked pid = % d/N", getpid (), pid );
If (PID <0)
{
Printf ("error in fork! /N ");
Getchar ();
Exit (1 );
}
Else if (pid = 0)
Printf ("/n [% d] In child process, p_id = % d/N", getpid (), getpid ());
Else
{
Printf ("/n [% d] in parent process, my pid = % d/N", getpid (), pid );
Printf ("/n [% d] in parent process, my getpid = % d/N", getpid (), getpid ());
}
}
The program running result is as follows:
$./Fork
[1, 3819] Not fork
[1, 3820] forked pid = 0
[3820] In child process, p_id = 3820
[1, 3819] forked pid = 3820
[1, 3819] in parent process, my pid = 3820
[3819] in parent process, my getpid = 3819
We can clearly see that not fork is printed only once. [3819] indicates the process Number of the parent process. After fork is created, the value PID returned by the fork function to the parent process is the process number of the child process [3820]. In the child process, the PID value is zero. That is to say, the PID is set to zero in the sub-process. According to a netizen on the Internet, "In fact, it is equivalent to a linked list. The process forms a linked list. The parent process PID (P means point) points to the sub-process ID because the sub-process has no sub-process, so its PID is 0."
An interesting program:
Int main ()
{
Int I;
For (I = 0; I <3; I ++)
{
Int pid = fork ();
If (pid = 0)
{
Printf ("Son/N ");
}
Else
{
Printf ("Father/N ");
}
}
Return 0;
}
Let's think about how many father sons will appear in the end ?.......
Right answer:
$./Fork
Father
Son
Son
Son
Father
Father
Son
Father
Son
Son
Father
Father
Son
Father
A total of 7 son7 father. Are you correct? This question needs to be painted on paper to understand for I = 0 1 2 Father son father son. Each row represents the running result of a process. When a child process is generated, the child process prints son. When the child process calls fork to generate the child process, the child process is promoted to father. To sum up, Father always prints father. Son is son before fork. After fork, It is father and a new son is generated.