> In any case, the "Multithreaded Singleton" problem is devilishly difficult to write and full of subtleties.
First off, global state does not necessarily require the singleton pattern.
But let's assume that we really need it, e.g. to create a global resource only on demand. This is how it's done in C++:
class Foo {
public:
static Foo& getInstance() {
// Since C++11, local static variable initialization is thread-safe!
static Foo instance;
return instance;
}
private:
Foo() {
// expensive constructor
}
};
I mostly use C++ and various scripting languages, but judging from the examples in
https://en.wikipedia.org/wiki/Double-checked_locking it seems like C#, Java and Go all have at least one simple and safe method to achieve this.
> Global state is important in many cases and cannot be avoided, and threads absolutely complicate it even more than usual.
If you depend on global state in the parent process, how can the subprocesses even operate, since they do not have access to that state? Yes, certain resources, such as loggers, need to be global, but these should really be thread-safe anyway.
> You haven't listed off what makes threads actually easier yet.
* creating and joining threads (in a portable way!) is trivial in most programming languages; creating and joining subprocesses not so much
* exchanging data much easier, no marshalling needed
* logging is much easier
* error handling is much easier
* debugging is much easier. (How do you debug a short lived subprocess? The process terminates before the debugger even has a chance to attach to it.)
> You're saying "mutexes and queues" are easier, and I disagree.
Maybe I was not clear, I was really talking about concurrent queues. The producer can push messages, the consumer waits on messages and processes them. It works basically like a pipe/FIFO, but without the pitfalls.
> > If one thread crashes, the whole process dies. There is no consistency problem here.
> Are you sure?
> Lets say I pthread_cancel() one of your threads. Is that cool?
I was talking about threads crashing.
> If thread #45 accepts() a connection, then gets pthread_cancel()d,
pthread_cancel() is dangerous, I agree. Generally, you should not use it. (I have never needed it.) There are much saner ways to "cancel" a thread, depending on your language. Often it's enough to periodically check a boolean flag.
> Lets compare / contrast with kill(SIGKILL), which is still dangerous but... the state of a process is far more consistent.
Yeah, it is easy to kill a subprocess. But let's consider the opposite: what happens if the parent process dies? How do you make sure that a long running subprocess automatically terminates? It is definitely not trivial.
---
It's fine if you like subprocesses. I just wanted to challenge the notion that they are somehow easier to use than threads - which just doesn't match my experience. We are probably working in entirely different domains, so it's natural that our experiences differ.