Earlier quoted context omitted.
You can have your cake and eat it too -- there's no throwing away of performance gains. Libraries can use threads, but not directly or "silently". They should take threads as parameters. Then the application knows when they're being used and the application programmer can reason about it.
compilers and runtimes can spawn threads implicitly when required (think of openmp, cilk+, or even autopar). Are you saying that libraries shouldn't use these facilities?
Fork() without exec() is dangerous in large programs
51–60 of 106 posts
Re: Fork() without exec() is dangerous in large programs
#52Earlier quoted context omitted.
I would like to see the reasons this comment was down-voted. It is true that fork(2) is simple and elegant design, but it involves a huge accidental complexity and hidden implications like in the original article. There is a reason that Linux has clone(2) underneath.
> It is true that fork(2) is simple and elegant design What exactly is simple and elegant about it? Have you looked into how much tooling is necessary everywhere in unix to make it work? It's insane. It has a huge footprint and it does not provide standardized APIs to make it work for non covered cases (the best we have is pthread_atfork which is not portable).
Spawn-style APIs have to take a billion parameters that are mostly set to defaults, for things like working directory, environment variables, user ID, controlling terminal. Whereas fork+exec means you can express these things in a more compositional, buildery style: fork, change the two things you actually need to change, then exec.
Re: Fork() without exec() is dangerous in large programs
#53Earlier quoted context omitted.
I would like to see the reasons this comment was down-voted. It is true that fork(2) is simple and elegant design, but it involves a huge accidental complexity and hidden implications like in the original article. There is a reason that Linux has clone(2) underneath.
> It is true that fork(2) is simple and elegant design What exactly is simple and elegant about it? Have you looked into how much tooling is necessary everywhere in unix to make it work? It's insane. It has a huge footprint and it does not provide standardized APIs to make it work for non covered cases (the best we have is pthread_atfork which is not portable).
Re: Fork() without exec() is dangerous in large programs
#54> How to use fork safely: 1. Only use fork to immediately call exec. 2. Fork a worker at the beginning of your program, before there can be other threads. 3. Only use fork in toy programs. 4. Stop writing broken multithreaded code altogether or if you must at least run an event loop per core/thread and use a wrapper for fork() to put the system into a fork()able state before forking. It's nice and reliable. Multithre…
Re: Fork() without exec() is dangerous in large programs
#55Earlier quoted context omitted.
Fork is simple, but not easy.
What makes for simple? I really need to understand this. I implemented fork many years ago for a university operating system and nothing about either the implementation nor the usage is simple. I use fork on a daily basis and the POSIX version of it is insanely complex for everybody involved.
Me too. I found it simple: Create new child process, copy the address space, copy the instruction pointer, let it run.
If you want to improve performance via copy-on-write, it gets more complex to implement. If you combine it with other features like threads, mmap, limits, etc use becomes complex, but the mechanism itself is simple.
You might be able to design an easy variant of fork, which handles threads, mmap, limits, etc in a sane way, but that would not be simple anymore.
Fork is actually a good example, why simple and easy are different concepts and why it is really hard to achieve both.
Re: Fork() without exec() is dangerous in large programs
#56I ran into this exact problem recently in a multithreaded Python app and spent two days trying to figure out wtf was going on. The multiprocessing spawn startup mode that was added in 3.4 solves this for most use cases at the expense of a small performance hit. For 2.x you are SOL however.
Re: multiprocessing in 3.4: I think it is unfortunate that due to backwards compatibility, the "forkserver" mode can't become the default on Unix, since it would help avoid this particular issue.
Re: Fork() without exec() is dangerous in large programs
#57If you are in control of all the threads that an application is running, you can call fork() safely by making sure the threads are put in a safe state (no critical locks retained) when the fork() call happens. Also note that many things that should normally be unsafe, like having running threads calling malloc() while another thread is forking, are actually safe in the real world using certain implementation of fork,…
Re: Fork() without exec() is dangerous in large programs
#58In my opinion, it's libraries that secretly use threads under the covers (but still access state shared with the rest of the program like the malloc heap) that are what's dangerous.
Yes. Libraries should provide algorithms and data structures, and parameterize a threading interface if necessary (though I think it's usually not necessary). Applications can then instantiate their own threads and pass them to the library (i.e. dependency injection.) So if you have 10 different concurrent libraries in an application, then you don't end up with 10 different threading paradigms or 10 different thread…
True, but they're more often used as a crutch where a select-style loop and/or state machine would be more suitable, leaving race conditions in their wake.
Re: Fork() without exec() is dangerous in large programs
#59> How to use fork safely: 1. Only use fork to immediately call exec. 2. Fork a worker at the beginning of your program, before there can be other threads. 3. Only use fork in toy programs. 4. Stop writing broken multithreaded code altogether or if you must at least run an event loop per core/thread and use a wrapper for fork() to put the system into a fork()able state before forking. It's nice and reliable. Multithre…
If you want a series of worker threads that are effectively the same as the master/initial thread. The proper way to do this clone(2) not fork, or fork/exec.
When used properly clone allows your group of threads to share a single PID, and TGID (Thread Group IDentifier). This cuts down on kernel resources your process(es) are using. They can natively share file descriptors and memory between each other (improving cache coherence). Also their signals are handled globally for all threads at once, not each thread managing it's own signals like Fork/Exec will result in.
Re: Fork() without exec() is dangerous in large programs
#60It sounds like if you use threads and fork it might be a disaster. Its true, but the author blames only fork and skip the second part of the problem, threads. This is not fair, because fork is much older than POSIX threads. In fact, POSIX threads were poorly designed to use with fork.