In the simplest cases, the behavior of fork() very simple - if you figured it out a bit in your first encounter with it. It either returns once with an error, or returns twice, once in the original (parent) process and once in a completely new, almost exact copy of the original process (child process). Upon return, these two processes are nominally independent, although they have many resources.
pid_t original = getpid(); pid_t pid = fork(); if (pid == -1) { …handle error situation… } else if (pid == 0) { assert(original == getppid() || getppid() == 1); assert(original != getpid()); …be childish here… } else { assert(original != pid); …be parental here… }
A child process is a copy of a parent. It has the same set of open file descriptors, for example; each file descriptor N opened in the parent object is open in the child element and they have the same open file description. This means that if one of the processes changes the position of the read or write in the file, it also affects the other process. On the other hand, if one of the processes closes the file, which does not directly affect the file in the other process.
This also means that if data was buffered in the standard I / O package in the parent process (for example, some data was read from the standard input file descriptor ( STDIN_FILENO ) to the data buffer for stdin , then this data is available to both the parent and the child and both can read this buffered data without affecting the other, which will also display the same data.On the other hand, after reading the buffered data, if the parent reads another buffer full, which moves the current file position for both the parent and the child, so then the child will not see the data that the parent just read (but if the child also reads the data block, the parent will not see this). This can be confusing. Therefore, it is usually recommended to make sure there is no pending standard input / output before forcing - fflush(0) is one way to do this.
In the code snippet assert(original == getppid() || getppid() == 1); it is possible that by the time the child completes the statement, the parent process may have quit, in which case the child will be inherited by a system process - which usually has PID 1 (I don’t know any POSIX systems where orphans are inherited other PID, but there is probably one).
Other shared resources, such as memory mapped files or shared memory, are still available in both. The subsequent behavior of the memory mapped file depends on the parameters used to create the mapping; MAP_PRIVATE means that two processes have independent copies of data, and MAP_SHARED means that they use the same copy of data, and changes made by one process will be visible in another.
However, not every program that plugs in is as simple as the story described so far. For example, a parent process might acquire some (advisory) locks; these locks are not inherited by the child. A parent can be multithreaded; the child has one thread of fulfillment - and there are restrictions placed on what the child can do safely.
The POSIX specification for fork() details the differences:
The fork() function should create a new process. The new process (child process) must be an exact copy of the calling process (parent process), except as described below:
The child process must have a unique process identifier.
The child process ID must also not match the active process group ID.
The child process must have a different parent process identifier, which must be the process identifier of the calling process.
The child process must have its own copy of the parent file descriptors. Each of the descriptors of the child files must refer to the same description of the open file with the corresponding file descriptor of the parent.
The child process must have its own copy of the threads of the parent open directories. Each open directory stream in the child process can share the directory positioning with the corresponding directory stream of the parent element.
The child process must have its own copy of the parent message directory descriptors.
The values of the child process tms_utime , tms_stime , tms_cutime and tms_cstime must be set to 0.
The time remaining until the alarm is reset to zero, and the alarm, if any, should be canceled; see the alarm.
[XSI] ⌦ All semadj values must be cleared. ⌫
File locks set by the parent process must not be inherited by the child process.
The set of pending child process signals is initialized to an empty set.
[XSI] ⌦ The interval timer must be reset in the child process. ⌫
Any semaphores open in the parent process must also be open in the child process.
[ML] ⌦ The child process must not inherit the address space memory locks set by the parent process through calls to mlockall() or mlock() . ⌫
Memory mappings created in the parent are stored in the child process. MAP_PRIVATE mappings inherited from the parent must also be MAP_PRIVATE mappings in the child, and any data changes in these mappings made by the parent before calling fork() must be visible to the child. Any changes to the data in the MAP_PRIVATE mappings made by the parent after fork() returns should only be visible to the parent. Modifications to data in MAP_PRIVATE mappings made by a child should only be visible to the child.
[PS] ⌦ For scheduling policies SCHED_FIFO and SCHED_RR, the child process must inherit the policy and priority settings of the parent process during the fork() function. For other planning policies, the policy and priority settings on fork() determined by implementation. ⌫
Timers for each process created by the parent must not be inherited by the child process.
[MSG] ⌦ The child process must have its own copy of the parent's message queue descriptors. Each of the child's message descriptors must refer to the same open message queue description as the corresponding parent message descriptor. ⌫
No asynchronous input or asynchronous output operations should be inherited by a child process. Any use of asynchronous control units created by the parent causes undefined behavior.
A process must be created in a single thread. If a multi-threaded process calls fork() , the new process should contain a replica of the calling thread and its entire address space, possibly including the state of the mutexes and other resources. Therefore, in order to avoid errors, the child process can only perform operations with the asynchronous signal until one of the exec functions is called. The fork handlers can be set using the pthread_atfork() function to support application invariants on fork() calls.
When an application calls fork() from a signal handler, and any of the fork handlers registered by pthread_atfork() calls a function that is not safe for the asynchronous signal, the behavior is undefined.
[OB TRC TRI] ⌦ If the Trace option and the Trace Inherit option are supported:
If the calling process is tracked in a trace stream that has its own inheritance policy set to POSIX_TRACE_INHERITED, the child process must be traced to this trace stream, and the child process must inherit the parent mapping of trace event names for the type trace event. If the trace stream in which the calling process is tracked has its inheritance policy set to POSIX_TRACE_CLOSE_FOR_CHILD, the child process should not be traced to this trace stream. The inheritance policy is set by calling posix_trace_attr_setinherited() . ⌫
[OB TRC] ⌦ If the Trace parameter is supported, but the Trace Inherit option is not supported:
A child process must not be traced to any of the trace streams of its parent process. ⌫
[OB TRC] ⌦ If the Trace option is supported, the child process of the trace controller process should not control the trace flows controlled by its parent process. ⌫
[CPT] ⌦ The initial value of the CPU hours of the child process must be set to zero. ⌫
[TCT] The initial CPU time for one thread of the child process must be set to zero.
, POSIX.1-2008, . , POSIX.1-2008, POSIX.1-2008.
fork() , , .
, , . POSIX fork() .
, . . , , () COW - - , , . ; . , , , fork() - ( , exec*() ). , , - . open() dup2() requires a discussion of the differences between file descriptors and descriptions of open files.