133

In Unix whenever we want to create a new process, we fork the current process, creating a new child process which is exactly the same as the parent process; then we do an exec system call to replace all the data from the parent process with that for the new process.

Why do we create a copy of the parent process in the first place and not create a new process directly?

1

7 Answers 7

83

The short answer is, fork is in Unix because it was easy to fit into the existing system at the time, and because a predecessor system at Berkeley had used the concept of forks.

From The Evolution of the Unix Time-sharing System (relevant text has been highlighted):

Process control in its modern form was designed and implemented within a couple of days. It is astonishing how easily it fitted into the existing system; at the same time it is easy to see how some of the slightly unusual features of the design are present precisely because they represented small, easily-coded changes to what existed. A good example is the separation of the fork and exec functions. The most common model for the creation of new processes involves specifying a program for the process to execute; in Unix, a forked process continues to run the same program as its parent until it performs an explicit exec. The separation of the functions is certainly not unique to Unix, and in fact it was present in the Berkeley time-sharing system, which was well-known to Thompson. Still, it seems reasonable to suppose that it exists in Unix mainly because of the ease with which fork could be implemented without changing much else. The system already handled multiple (i.e. two) processes; there was a process table, and the processes were swapped between main memory and the disk. The initial implementation of fork required only

1) Expansion of the process table

2) Addition of a fork call that copied the current process to the disk swap area, using the already existing swap IO primitives, and made some adjustments to the process table.

In fact, the PDP-7's fork call required precisely 27 lines of assembly code. Of course, other changes in the operating system and user programs were required, and some of them were rather interesting and unexpected. But a combined fork-exec would have been considerably more complicated, if only because exec as such did not exist; its function was already performed, using explicit IO, by the shell.

Since that paper, Unix has evolved. fork followed by exec is no longer the only way to run a program.

  • vfork was created to be a more efficient fork for the case where the new process intends to do an exec right after the fork. After doing a vfork, the parent and child processes share the same data space, and the parent process is suspended until the child process either execs a program or exits.

  • posix_spawn creates a new process and executes a file in a single system call. It takes a bunch of parameters that let you selectively share the caller's open files and copy its signal disposition and other attributes to the new process.

2
  • 12
    Nice answer but I would add that vfork shouldn't be used used anymore. The performance difference is marginal now and its use can be dangerous. See this SO question stackoverflow.com/questions/4856255/…, this site ewontfix.com/7, and "Advanced Unix Programming" page 299 about vfork Jun 12, 2014 at 4:51
  • 4
    The machinations (data structure setup) required to use posix_spawn() to do the same post-fork replumbing jobs that can be done easily using fork() and inline code makes a compelling argument for fork() being much simpler to use. Jun 12, 2014 at 23:41
45

[I'll repeat part of my answer from here.]

Why not just have a command that creates a new process from scratch? Isn't it absurd and inefficient to copy one that is only going to be replaced right away?

In fact, that would probably not be as efficient for a few reasons:

  1. The "copy" produced by fork() is a bit of an abstraction, since the kernel uses a copy-on-write system; all that really has to be created is a virtual memory map. If the copy then immediately calls exec(), most of the data that would have been copied if it had been modified by the process's activity never actually has to be copied/created because the process doesn't do anything requiring its use.

  2. Various significant aspects of the child process (e.g., its environment) do not have to be individually duplicated or set based on a complex analysis of the context, etc. They're just assumed to be the same as that of the calling process, and this is the fairly intuitive system we are familiar with.

To explain #1 a little further, memory which is "copied" but never subsequently accessed is never really copied, at least in most cases. An exception in this context might be if you forked a process, then had the parent process exit before the child replaced itself with exec(). I say might because much of the parent could be cached if there is sufficient free memory, and I am not sure to what extent this would be exploited (which would depend on the OS implementation).

Of course, that doesn't on the surface make using a copy more efficient than using a blank slate -- except "the blank slate" is not literally nothing, and must involve allocation. The system could have a generic blank/new process template that it copies the same way,1 but that would then not really save anything vs. the copy-on-write fork. So #1 just demonstrates that using a "new" empty process would not be more efficient.

Point #2 does explain why using the fork is likely more efficient. A child's environment is inherited from its parent, even if it is a completely different executable. For example, if the parent process is a shell, and the child a web browser, $HOME is still the same for both of them, but since either could subsequently change it, these must be two separate copies. The one in the child is produced by the original fork().

1. A strategy that may not make much literal sense, but my point is that creating a process involves more than copying it's image into memory from disk.

15
  • 3
    While both points are true, neither supports why forking method was chosen instead of reating a new process from given executable. Jun 11, 2014 at 20:06
  • 3
    I think this does answer the question. Fork is used because, in cases where creating a new process is the most efficient way to go, the cost of using fork instead is trivial (likely less than 1% of the process creation cost). On the other hand, there are many places where fork is dramatically more efficient or far simpler of an API (such as handling file handles). The decision Unix made was to only support one API, making the specification simpler.
    – Cort Ammon
    Jun 12, 2014 at 1:34
  • 1
    @SkyDan You're right, it's more an answer to why not rather than why, which Mark Plotnick answers more directly -- which I would interpret to mean not just that this was the easiest choice, but also that it was probably the most efficient choice (according to the Dennis Richie quote: "the PDP-7's fork call required precisely 27 lines of assembly...exec as such did not exist; its function was already performed"). So this "why not" is really a musing about two strategies wherein one superficially appears simpler and more efficient, when perhaps it isn't (witness the dubious fate of...
    – goldilocks
    Jun 12, 2014 at 7:46
  • 2
    The original Unix implementations didn't have virtual memory or copy-on-write. So while this explains why fork() is cheap now, it doesn't motivate why the model was chosen in the first place.
    – Barmar
    Jun 18, 2014 at 20:54
  • 2
    Your answer referred to the hardware improvements: virtual memory, copy-on-write. Before these, fork actually copied all the process memory, and it was very expensive.
    – Barmar
    Jun 19, 2014 at 4:00
10

I think the reason Unix had only the fork function to create new processes is a result of the Unix philosophy

They build one function that does one thing well. It creates a child process.

What one does with the new process is then up to the programmer. He can use one of the exec* functions and start a different program, or he could not use exec and use the two instances of the same program, which can be useful.

So you get a bigger degree of freedom since you can use

  1. fork without exec*
  2. fork with exec* or
  3. just exec* without fork

and in addition you only have to memorize the fork and the exec* function calls, which in the 1970s you had to do.

3
  • 3
    I understand how forks work, and how to use them. But why would I want to create a new process, when I can do the same thing but with less effort? For example, my teacher gave me an assignment where I had to create a process for each number passed to argv, to check if the number is a prime. But isn't that just a detour of ultimately doing the same thing? I could've just used an array and used a function for each number... So why do we create child processes, instead of doing all the processing in the main process? Dec 3, 2015 at 1:41
  • 4
    I would venture to say that you understand how forks work, and how to use them, because you once had a teacher who gave you an assignment where you had to create a bunch of processes (with the number being specified at run-time), control them, co-ordinate them, and communicate among them. Of course nobody would do something trivial like that in real life. But, if you have a large problem that is easily decomposed into pieces that can be handled in parallel (e.g., edge detection in an image), forking lets you use multiple CPU cores simultaneously. Aug 11, 2017 at 18:05
  • You can use threads to run code on multiple CPU cores, you don't need a whole process for that. The advantage of using a separate process lies more in gaining more protection. E.g. if you were doing something more complex than check if a number is prime, and it crashed, it wouldn't take down your entire parent process, you would just lose the one result. Also, you can reduce a process's privileges. E.g. if the parent runs as root, you can run the child process as the currently-logged-in user, so if there's an exploit in the child process code, it can't access other users' files.
    – uliwitness
    Mar 23 at 13:45
6

There are two philosophies of process creation: fork with inheritance, and create with arguments. Unix uses fork, obviously. (OSE, for example, and VMS use the create method.) Unix has MANY inheritable characteristics, and more get added periodically. Via inheritance, these new characteristics can be added WITHOUT CHANGING EXISTING PROGRAMS! Using a create-with-arguments model, adding new characteristics would mean adding new arguments to the create call. The Unix model is simpler.

It also affords the highly useful fork-without-exec model, where a process can split itself into multiple pieces. This was vital back when there was no form of async I/O, and is useful when taking advantage of multiple CPU's in a system. (Pre-threads.) I've done this a lot over the years, even recently. In essence it allows for container-izing multiple 'programs' into a single program, so there is absolutely no room for corruption or version mismatches, etc.

The fork/exec model also affords the ability for a specific child to inherit a radically weird environment, set up between the fork and the exec. Things like inherited file descriptors, especially. (An extension of stdio fd's.) The create model doesn't offer the ability to inherit anything that wasn't envisioned by the creators of the create call.

Some systems also can support dynamic compilation of native code, where the process is in effect writing its own native-code program. In other words, it wants a new program that it is writing itself on the fly, WITHOUT having to go through the source-code/compiler/linker cycle, and occupying disk space. (I believe there is a Verilog language system that does this.) The fork model supports this, the create model normally would not.

1
  • File descriptors are not “an extension of stdio”; stdio file pointers are a wrapper around file descriptors. File descriptors came first, and they are the fundamental Unix I/O handles. But, otherwise, this is a good point. Aug 11, 2017 at 18:51
2

The fork() function isn't only to copy the father process, it returns a value which refer that the process is the father or the son process, the image below explain how can you make use of fork() as a father and a son:

enter image description here

as shown when the process is the father fork() returns the son process ID PID else it returns 0

for example you can make use of it if you have a process ( web server ) that receive the requests and on each request it create a son process to process this request, here the father and its sons have different jobs.

SO, no run a copy of a process isn't the exact thing as fork().

3
  • 5
    While it is true, this does not answer the question. Why is forking necessary for process creation, if I want to run a different executable? Jun 12, 2014 at 4:39
  • 1
    I agree with SkyDan – this does not answer the question. posix_spawn is a somewhat fancier version of what might have been imagined 30 years ago (before Posix existed) as a fork_execve function; one that creates a new process, initializing its image from an executable, without even hinting at copying the image of the parent process (except for the argument list, the environment, and the process attributes (e.g., working directory)), and returns the PID of the new process to the caller (the parent process). Jun 12, 2014 at 18:55
  • 1
    There are other ways to pass "parent" information to a child. The return value technique just happens to be the most efficient way of doing it from a fork if you assume you want fork in the first place
    – Cort Ammon
    Jun 12, 2014 at 22:59
0

I/O redirection is most easily implemented after fork and before exec. The child, being aware it's the child, can close file descriptors, open new ones, dup() or dup2() them to get them onto the right fd number, etc, all without affecting the parent. After doing that, and perhaps any desired environment variable changes (also not affecting the parent), it can exec the new program in the tailored environment.

1
-2

I think everyone here knows that how fork is work,but the question is that why we need to create exact duplicate of parent using fork? Answer==>Take an example of server (without fork),while client-1 is accessing the server,if at the same time second client-2 is arrived and wants to access the server but server not give the permission to the newly arrived client-2 because server is busy to serve client-1 so client-2 has to wait.after all the services to the client-1 is finish,client-2 is now able to access the server.Now consider if at the same time client-3 arrive ,so client-3 has to wait till all the services to the client-2 is finish.Take the scenario where the thousands of clients need to access the server at the same time...then all the clients has to wait(server is busy!!).

This is avoided by creating(using fork)exact duplicate copy(i.e child) of server,where each child (which is exact duplicate copy of its parent i.e server) is dedicated to the newly arrived client,thus simultaneously all the clients access the same server.

1
  • This is why server processes should not be single-threaded, handling client requests consecutively when they can be handled concurrently — e.g., in separate processes.  But the multi-threaded server model can easily be implemented with a listener process that accepts requests from clients and creates a brand new process in which to run the client-service program. The only advantage that is offered by the fork call that copies the parent process is that you don’t have to have two separate programs — but having separate programs (e.g., inetd) can make the system more modular. Aug 11, 2017 at 18:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .