4 ms·
Well, there are two categories of problems. One is that fork() is by definition a very costly operation (a copy of the entire address space of the current proc
by tsimionescu 3y ago
Well, there are two categories of problems.
One is that fork() is by definition a very costly operation (a copy of the entire address space of the current process), and the kernel has to do a lot of work to implement it efficiently (implementing copy-on-write clones of all of the pages of a process). And that all that work is done for nothing in the very very very common case of doing fork() + exec().
The other problem is that the semantics of fork() just fundamentally can't work properly for a multi-threaded process. In any multi-threaded process, if you do fork(), the only thing you can safely do in the child process is to call exec(). Any other call, even a printf() or some path logic, has a very good chance to lead to a deadlock, quite possibly inside malloc() itself.
So fork() as a standalone operatikn is actually an extremely niche utility (duplictaing single-threaded processes) that has been made the main way of spawning new processes. Similarly, exec() by itself is an even more niche utility, sometimes useful for "launcher" style processes.
So, instead of achieving an extremely common task (launch some binary file as a new process) using a dedicated system call, Unix has chosen to define two extremely niche syscalls that you should almost never use individually, but that together can implement this common process, but only with a lot of behind the scenes work to make it efficient.
- IsTom 3y ago> One is that fork() is by definition a very costly operation Isn't process creation much slower on Windows (not using fork) than forking on Unix-likes?
- tsimionescu 3y agoIt is, but there are many other differences between Unix and Windows processes than just fork() VS CreateProcess(). Even disregarding this, the actual fork() syscall has had many hundreds of dev hours poured into it to implement the costly semantics (copy all resources) in an efficient way for the common use case (copy-on-write semantics).
- Joker_vD 3y agoAlso, fork() interacts very poorly with e.g. CUDA: turns out, you can't fork the GPU itself.
- bluetomcat 3y agoThe way the shell works is an essential part of Unix design, and the fork/exec pair suits it very well. In the forked child process before the exec, the shell can execute arbitrary code that inherits all file descriptors and manipulates/redirects them in a certain way.
- tsimionescu 3y agoI didn't say it's useless, I said it's a niche utility. There are, what, 10 even slightly commonly used shells? Compared to the thousands of other programs that spawn processes, I think shells count as a niche use. If fork() and exec() had been kept as the niche utilities they are in addition to a more commonly used spawn() syscall, fork() and exec() could have remained simple and small, and not needed all the CoW magic and many other complex features at all.
- hawski 3y agoI wonder now if one could emulate fork-shenanigans-exec by: - clone CLONE_FILES with AF_UNIX socketpair - send file descriptors through the socket - do whatever was in shenanigans (you have the socket for communication/RPC/whatever) - exec or maybe even easier: - clone CLONE_FILES with pipe or two - do whatever was in shenanigans (you have the pipe for communication/RPC/whatever) - exec
- knightoffaith 3y agoWhat do people who care a lot about latency do about this? Do they have no choice but to eat the cost of fork()?
- hnlmorg 3y agoThey avoid spawning new processes.