On Sun, Feb 20, 2011 at 6:28 AM, Samuel Adam <[email protected]> wrote:
> On Sat, 19 Feb 2011 17:12:31 -0500, Pavel Ivanov <[email protected]>
> wrote:
>
>> [snip] On
>> Windows it’s different - process is much more heavy-weight object than
>> thread and involves much bigger system load to support it. There’s an
>> official general advice for Windows: better create a new thread in the
>> same process than a new process.
>
> Mr. Ivanov explained what I was saying better than I did.  My unclear
> offhand comment about fork()/exec() was an allusion to why *nix developed
> much lighter-weight processes than Windows, viz., decades of a
> fork()/exec() custom and practice.  (Indeed, I believe that’s precisely
> why Linux went to the trouble of re-engineering fork() with COW.)  I
> intended to address the overhead of running, and inadvertently introduced
> a red herring about overhead of starting.

You seem to be conflating the weightiness of a notion of process with
the weightiness of interfaces for creating processes.

fork() has nothing to do with whether a notion of process is
light-weight or not.  And quite aside from that, fork() is only as
light-weight as the writable resident set size of the parent process.
Long, long ago fork() would copy the parent's address space.  Later on
fork() implementations started marking what should be writable pages
as read-only in the MMU page table entries for the process in order to
catch writes and then copy-on-write.  COW works fine for
single-threaded processes when the child of fork() intends to exec()
or exit() immediately and the parent is willing to wait for the child
to do so.  But for a heavily multi-threaded process with a huge RSS,
such as a web browser, COW is a performance disaster as it means
cross-calls to do MMU TLB shoot down, and then incurring a potentially
large number of page faults in the parent as those threads continue
executing.  Nowadays it's often simpler and faster to just copy the
writable portion of the parent's RSS...  vfork(), OTOH, need only
result in cross-calls to stop the parent's threads, but no page table
manipulations, TLB shootdowns, data copies, nor page faults need be
incurred.  And a true posix_spawn() wouldn't even have to stop the
parent's threads (but using vfork() makes posix_spawn perform so well
compared to fork() that, for example, Solaris' posix_spawn() just uses
vfork()).  In Solaris, for example, we've obtained major performance
improvements by having applications such as web browsers use
posix_spawn() or vfork() in preference to fork().

In any case, fork() is not an essential attribute of an operating
system's notion of "process", but an incidental one (related to how
one creates processes).  In terms of essential attributes, Unix and
Windows processes compare to each other, and Windows and Unix threads
(POSIX threads) also compare to each other (roughly anyways, as some
pthreads implementations have M:N mappings to kernel constructs while
others have 1:1, and so on).  Yes, Linux has clone(2), which allows
one to decide just what parts of the parent's various attributes the
child will share with the parent or get a copy of from the parent, but
because the standard is pthreads, in practice most developers on Linux
constrain themselves to using pthreads, thus the concept of clone(2)
is not that relevant here.

> Speaking as a user, by the way, I don’t think I actually have *any*
> Windows applications which use worker processes for concurrency the same
> way my *nix server daemons do.  There’s a reason for that.

It's largely a cultural thing.  Windows NT and up had and promoted
threading from the get-go, while Unix had a very long tradition of
single-threaded processes, and some Unix systems had to catch up to
Windows regarding multi-threading.  There are many other factors
leading to this dichotomy, such as the fact that Unix developers tend
to appreciate isolation, the fact that Window's process spawn API is
so complex and difficult to use, the fact that Windows allows
individual threads of a process to execute with different access
tokens in effect (thus reducing the need to start additional
processes, even if this means losing a lot on the isolation front),
etcetera.  OTOH I've no reason to believe that this split has anything
to do with the weightiness of Windows processes vs. Unix ones (though
the complexity of creating new processes certainly is involved).  But
we do get many heavily multi-threaded applications on Unix nowadays.
Perhaps the Windows model won out... threads _are_ easier to get
started with than processes.

Obtopic: I've successfully used SQLite_2_ with pthreads, and have
every reason to believe that it is possible to safely and productively
use SQLite3 with pthreads.  The key for using SQLite3 in a
multi-threaded way is to adhere to good threaded programming
guidelines while thoroughly understanding the APIs you choose to use.
In particular you should do your utmost to minimize the use of any
sharing of state across threads, and you should understand the
pthreads APIs as well as membars and atomic operations provided
outside pthreads.

Nico
--
_______________________________________________
sqlite-users mailing list
[email protected]
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to