Transferred from UNIX environment advanced programming + personal supplement
Calling the f o r k function by an existing process is the only way for the u n I X Kernel to create a new process (this is not applicable to the preceding Section
And the exchange process, I n I t process, and page genie process. These processes are part of the self-lifting process by the kernel in a special way.
Created ).
# I nclude <sys/types. h>
# I nclude <unistd. h>
Pid_t fork (void );
Return Value: 0 for the child process, I d for the parent process, and-1 for the error.
A new process created by f o r k is called a child process ). This function is called once, but returns twice. Two replies
The difference is that the return value of the child process is 0, and the return value of the parent process is the process I d of the new Child process. Returns the sub-process I d
The reason for giving the parent process is: because a process can have more than one sub-process, there is no function to make a process
Obtain the process I D of all its sub-processes. F o r k causes the sub-process to get the return value 0: A process has only one parent
So the sub-process can always call g e t p I d to obtain the process I D of its parent process (process ID 0 is always used by the exchange process,
Therefore, the process I D of a sub-process cannot be 0 ).
Sub-processes and parent processes continue to execute commands after f o r k. A child process is a replica of the parent process. For example, the sub-process obtains
Copies of the data space, heap, and stack of the parent process. Note that this is a copy of the sub-process. Parent and Child processes do not share this
Storage space. If the body segment is read-only, the Parent and Child processes share the body segment (see section 7. 6 ).
At present, many implementations do not make a full copy of the Data Segment and heap of the parent process, because f o r k often follows
E x e c. As an alternative, the replication technology (c o p y-o n-write, cow) is used during write. These regions are composed of parent and child Processes
And the kernel changes their access permission to read-only. If a process attempts to modify these regions
A typical part is the "page" in the virtual storage system for a copy. Section 9. 2 of Section B A C H [1 9 8 6] and Section L e ff L E R [1 9 8 9 〕
In section 5. 7.
Instance
The code 8-1 represents the f o r k function. If you execute this program, you will get:
$ A. O U T
A write to stdout
Before fork
PID = 430, glob = 7, Var = 89 the variable value of the sub-process has changed
PID = 429, glob = 6, Var = 88 the variable value of the parent process has not changed
$ A. Out> temp. Out
$ Cat temp. Out
A write to stdout
Before fork
PID = 432, glob = 7, Var = 89
Before fork
PID = 431, glob = 6, Var = 88
Generally, after f o r k, whether the parent process executes first or the child process executes first is uncertain. This depends on the kernel
Scheduling algorithm. If mutual synchronization is required between parent and child processes, some form of inter-process communication is required. In Program 8-1, the parent process slews itself for 2 seconds, so that the child process is executed first. But it is not guaranteed that 2 seconds is enough. In section 8
This issue and other types of synchronization methods will also be discussed during the competition. In section 1 0. 6, after f o r k, the Parent and Child processes are synchronized with signals.
Note: The relationship between f o r k and I/O functions in program 8-1. Recall that the w r I t e function is not cached as described in Chapter 3rd.
Because w r I t e is called before f o r k, the data is written to the standard output once. However, the standard I/O Library has a cache. Back
Recall section 5. 1 and section 2. If the standard output is connected to the terminal device, it will be cached in the row; otherwise, it will be fully cached. When interacting
When running the program, only the rows output by p r I n t f are obtained once, because the standard output cache is refreshed by the new line operator. However
When the standard output is redirected to a file again, the p r I n t f output line is obtained twice. The reason is that it was called before f o r k.
P r I n t f once, but when calling f o r k, the row of data is still in the cache, and then when the data space of the parent process is copied to the child process,
The cached data is also copied to the sub-process. At that time, the Parent and Child processes each had a cache containing the content of the row. In e x I t
The first second p r I n t f adds its data to the existing cache. When each process is terminated, the content in the cache is written
File.
Program 8-1 fork function instance
{
Window. Open (this. SRC );
} "Src =" http://www.blog.com.cn/user24/duanjianghu/upload/921680267.gif "alt =" ">
File Sharing
Note that when the standard output of the parent process is re-directed, the standard output of the child process is also
Redirect. In fact, one feature of f o r k is that all descriptors opened by the parent process are copied to the child process. Parent,
Each identical open descriptor of a sub-process shares a file table item (see Figure 3-3 ).
Consider the following situations where a process opens three different files: standard input, standard output, and standard error.
When returning from f o r k, we have the arrangement shown in 8-1.
This shared file method allows the Parent and Child processes to use a file displacement for the same file. Consider the following situations: 1.
Processes f o r k have a sub-process, and then wait for the sub-process to terminate. Assume that, as part of normal processing, the Parent and Child Processes
Write operations to the standard output. If the parent process redirects its standard output (probably implemented by s h e l ),
When a child process writes data to the standard output, it updates the amount of the file that is shared with the parent process. In our example,
When the parent process waits for the child process, the child process is written to the standard output. After the child process is terminated, the parent process is also written to the standard output,
It is also known that its output will be added after the data written by the child process. If the parent and child processes do not share the same file displacement
It is difficult to implement formal interaction.
{
Window. Open (this. SRC );
} "Src =" http://www.blog.com.cn/user24/duanjianghu/upload/921848055.gif "alt =" ">
If the parent and child processes write to the same descriptor file, but there is no form of synchronization (for example, the parent process waits for the child
(Assuming that the descriptor is opened before f o r k ). However
Is possible (see Program 8-1), but this is not a common operation method.
There are two common scenarios for processing file descriptors after f o r k:
(1) The parent process waits for the child process to complete. In this case, the parent process does not need to process its descriptor. When Sub-entry
After the end of the process, the file displacement of any shared descriptor that has been read or written has been updated accordingly.
(2) Parent and Child processes execute different program segments respectively. In this case, after f o r k, the Parent and Child processes are disabled respectively.
They do not need to use file descriptors and do not interfere with the file descriptors used by the other party. This method is in the network service process.
Frequently used.
In addition to opening files, many other properties of the parent process are also inherited by the child process:
* Actual user I d, actual group I d, valid user I d, and valid group I D.
* Add group I D.
* Process group I D.
* Session I D.
* Control terminal.
* Set-user-I d flag and set-group-I d flag.
* Current working directory.
* Root directory.
* Create a blocked word in the file mode.
* Signal shielding and arrangement.
* Disable the flag when executing any opened file descriptor.
* Environment.
* Shared storage segment of the connection.
* Resource restrictions.
The differences between parent and child processes are:
* Return value of fork.
* Process I D.
* Different parent process I D.
* The sub-process t m s _ u t I m E, t m s _ s t I m e, t m s _ c u t I m E and t m s _ u s t I m e are set to 0.
* The lock set by the parent process. The child process does not inherit the lock.
* Pending alarms of sub-processes are cleared.
* The pending Signal Set of the sub-process is set to an empty set.
Many of these features have been discussed at the end of this Article. We will describe them in the following chapters.
The two main reasons for the failure of f o r k are: (a) there are already too many processes in the system (which usually means that a problem occurs in some aspects.
), Or (B) the total number of processes of the actual user I d exceeds the system limit. Recall Table 2-7, where c h I L D _ m a x specifies
The maximum number of processes that an actual user I D can have at any time.
F o r k can be used in two ways:
(1) A parent process wants to copy itself so that the parent and child processes can execute different code segments at the same time. This is in the network service process
Is common-the parent process waits for the delegate's service request. When such a request arrives, the parent process calls f o r k
Process to process this request. The parent process continues to wait for the next service request.
(2) A process must execute a different program. This is a common case for s h e l. In this case, the sub-process
Call E x e c immediately after returning from f o r k (We will describe e x e c in Section 8. 9 ).
Some operating systems combine the two operations in (2) (F o r k and then execute e x e c) into one and call it s p a w n. U n I x
These two operations are separated because f o r k needs to be used separately in many cases, and it does not follow e x e c later. In addition
Separate operations so that sub-processes can change their attributes between f o r k and e x e c. For example, I/O redirection, user I d, mail
. There are many examples in Chapter 4.
Conclusion:
# I nclude <unistd. h>
# I nclude <stdio. h>
Int main ()
{
Int PID;
Int pid2;
// Printf ("% d", getppid ());
Printf ("===================/N ");
Printf ("lllllllllllllll ");
If (pid = fork () = 0 ){
Printf ("this is the child process: % d/N", pid );
}
Else
{
If (pid2 = fork () = 0)
Printf ("this is another child process: % d/N", pid2 );
Else
Printf ("this is the parent process: % d/N", PID, pid2 );
}
Printf ("--------/N ");
Return 1;
}
The output result is
==================
Lllllllllllllthis is the child process: 0
--------
Lllllllllllllthis is another child process: 0
--------
Lllllllllllllllthis is the parent process: 22180 22181
--------
# I nclude <unistd. h>
# I nclude <stdio. h>
Int main ()
{
Int PID;
Int pid2;
// Printf ("% d", getppid ());
// Printf ("=====================/N ");
Printf ("lllllllllllllll ");
If (pid = fork () = 0 ){
Printf ("this is the child process: % d/N", pid );
}
Else
{
If (pid2 = fork () = 0)
Printf ("this is another child process: % d/N", pid2 );
Else
Printf ("this is the parent process: % d/N", PID, pid2 );
}
Printf ("--------/N ");
Return 1;
}
Output result:
Lllllllllllllthis is the child process: 0
--------
Lllllllllllllthis is another child process: 0
--------
Lllllllllllllllthis is the parent process: 22212 22213
--------
The reason is:
The sub-process simultaneously copies the cached content of the parent process printf () for row caching and writes the data back to the standard output file after exit.