3 ms·
I suppose it might be possible to fix fork() but the performance costs might be prohibitive. The kernel would need to suspend any thread that attempts to take
by xenadu02 8y ago
I suppose it might be possible to fix fork() but the performance costs might be prohibitive.
The kernel would need to suspend any thread that attempts to take a lock or is not currently holding a lock. That immediately makes userland-only synchronization besides lockless impossible; the kernel has to know about the synchronization primitives.
Once all threads besides the forking thread are blocked trying to acquire a lock or suspended without holding any locks the process can fork and all threads resume.
A far better payoff might be making processes cheaper to create, faster to startup, and providing easier-to-use IPC mechanisms. Those things benefit lots of programs, not just esoteric uses of fork().
- comex 8y agoI don’t think that’s true. There’s nothing inherently bad about forking a thread while it’s holding a lock. The problem, rather, is with not forking a thread while it’s holding a lock. That is – from the child process’s perspective, it’s as if all the threads other than the one that called fork() were abruptly terminated. If any of those threads happened to be holding a lock, then it will never have the chance to finish whatever work it was doing and release the lock… because it no longer exists. On the other hand, if fork() cloned all threads in the process, then they they could keep synchronizing and working as usual, oblivious to the fact that they’re now in a new process. Well, mostly. One significant exception: Synchronization mechanisms sometimes identify threads internally using a system-global ID. For example, some variants of the Linux futex() syscall require you to write your thread ID, as returned by gettid(), to the lock word to indicate that the lock is owned by you. This obviously won’t work if a thread’s ID can change at any time; you would have to switch to some other ID that’s instanced per-process. Except that would break mutexes shared between processes using shared memory, so you’d have to find a different solution for that. Solvable, but not quite trivial. By the way, as a sort of existence proof, Linux already has a way to do something like multithreaded fork()! Namely, CRIU (“checkpoint restore in userland”), used with containers, is a program that can dump a process (or set of processes) to disk and restore them later – including multithreaded processes. This is normally used for things like migrating containers across physical machines, but AFAIK, in theory you could restore the same dump multiple times to get multiple copies of the same process; it would just be slow, and massively overkill. :) The catch: it relies on PID namespaces, such that all processes and threads get the same PIDs and TIDs after being restored as they had before – but they’re only unique within the PID namespace, i.e. container. Thus it doesn’t have to deal with the possibility of TIDs changing, but the process has to be isolated from others. For a container, isolation is what you want anyway, but it’s probably not what you want if you’re just a random Unix program trying to fork.