fork() is strictly superior to an API like Win32 CreateProcess(), because it can do more with less.
Processes normally inherit lots of context from their parent: the user identity, the window station (Win32-speak), security capabilities, I/O handles / console, environment variables, current directory, etc. The most logical way to inherit everything is to make a logical copy, which is very cheap owing to memory architecture.
Because of this things that would normally need two APIs, one synchronous and one asynchronous, can be programmed easily. If you need the synchronous version, call it directly; otherwise, fork and call it, and wait on the pid (at a later point) if necessary in the parent.
And I rather vehemently disagree with you saying that the threading model has less complications than the process model. I believe there's almost universal agreement that the problem with threading is mutable shared state, and the process model avoids it.
To see some of the hoops that need to jumped through to emulate fork() on systems that don't have it, and the limitations of doing so, check out the perlfork man page.
Processes normally inherit lots of context from their parent: the user identity, the window station (Win32-speak), security capabilities, I/O handles / console, environment variables, current directory, etc. The most logical way to inherit everything is to make a logical copy, which is very cheap owing to memory architecture.
Because of this things that would normally need two APIs, one synchronous and one asynchronous, can be programmed easily. If you need the synchronous version, call it directly; otherwise, fork and call it, and wait on the pid (at a later point) if necessary in the parent.
And I rather vehemently disagree with you saying that the threading model has less complications than the process model. I believe there's almost universal agreement that the problem with threading is mutable shared state, and the process model avoids it.