Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

pthread and async-signal safety.

936 views
Skip to first unread message

cinsk

unread,
Apr 17, 2009, 1:09:42 AM4/17/09
to
Hi.

Is there any signal-safe pthread function?

I searched SUS (POSIX) specification and I found no pthread_* function
in what they call async-signal-safe functions.

I searched this group and found that pthread_mutex_lock() should not
be used in a signal handler. What about other pthread_* functions?

If there are any document about it, please let me know.

AFAIK, at least pthread_sigmask() is async-signal-safe function.
Right?

George Peter Staplin

unread,
Apr 17, 2009, 5:02:11 AM4/17/09
to
cinsk wrote:

My understanding is that pthread_mutex_lock() is very likely to deadlock in
a signal handler. This is problematic for the implementation of some
things, because if say you implement a language on top of C, and you want
to expose signal handling with threads, you would need to use a mutex and
some sort of data structure in general. However, there is sometimes a way
around this. Depending on what you need, you may be able to use pipe() and
write() to the writable end of that pipe to notify some code path that the
signal occurred. You could have one thread waiting with select() for the
read end of the pipe to become readable. write() is async-signal safe, but
you probably won't have any way of reporting an error. perror() and
fprintf(stderr, ...); aren't safe in signal handlers. Also, be aware that
pipes can block with a write(), so you could create a deadlock situation if
enough is written without a corresponding read() or O_NONBLOCK with
fcntl().

Another thing people sometimes do is block all signals in all but one
thread, so that only one thread will get signals, and handle them. As it
is, a signal may go to a random thread, and not necessarily the thread that
set the signal handler. This is apparently true with signal() and
sigaction().

POSIX really in my opinion, did not fully solve the thread problem, and I
have doubts that they ever fully will. A related async-safety issue is
that fork() is useless with some systems when there are > 1 threads, and
it's prone to cause deadlocks on some others where it works.
pthread_atfork() isn't a solution either, due to async-safety requirements.
pthread_atfork() is more of a problem, because you can't use it to make
fork()ed mutex have the proper state, or recreate all of the other threads.
So, we must use posix_spawn() (an equivalent of fork() and exec*()) if we
want portability and threads, and fork() is now mostly useless. You also
can't expect to mix applications that use fork() with libraries that use
pthreads in a portable and reliable manner, which sometimes limits library
choices.

-George

Rainer Weikusat

unread,
Apr 17, 2009, 6:44:12 AM4/17/09
to
cinsk <cin...@gmail.com> writes:
> Hi.
>
> Is there any signal-safe pthread function?

No.

Rainer Weikusat

unread,
Apr 17, 2009, 6:58:43 AM4/17/09
to
George Peter Staplin <geor...@xmission.com> writes:
>> Is there any signal-safe pthread function?
>>
>> I searched SUS (POSIX) specification and I found no pthread_* function
>> in what they call async-signal-safe functions.
>>
>> I searched this group and found that pthread_mutex_lock() should not
>> be used in a signal handler. What about other pthread_* functions?

[...]

> My understanding is that pthread_mutex_lock() is very likely to
> deadlock in a signal handler.

However pthread_mutex_lock might be implemented, it is inconceivable
that it would 'likely deadlock' when called from a signal handler in
absence of deliberate sabotage. It is not async-signal safe, hence,
the behaviour is undefined if a signal handler whose execution
interrupted another unsafe function calls it.

> This is problematic for the implementation of some things, because
> if say you implement a language on top of C, and you want to expose
> signal handling with threads, you would need to use a mutex and some
> sort of data structure in general.

One solution for this is to use a POSIX semaphore, which may be posted
safely from a signal handler.

[...]

> Another thing people sometimes do is block all signals in all but one
> thread, so that only one thread will get signals, and handle them. As it
> is, a signal may go to a random thread, and not necessarily the thread that
> set the signal handler. This is apparently true with signal() and
> sigaction().

Presumably, it will be some thread which isn't already busy doing
something else, which makes sense on a multiprocessor.

> POSIX really in my opinion, did not fully solve the thread problem,
> and I have doubts that they ever fully will.

There are still people arguing that 'threads' as such need to be
uninvented because they (the people themselves) have trouble
understanding systems which consist of multiple, independently moving
parts (This is a common deficiency among a lot of people, but
typically, only professors of mathematics demand that everything else
needs to be adapated to them :->. I would second this, provided it can
be ascertained that none of them ever drives a car :->>).

> A related async-safety issue is that fork() is useless with some
> systems when there are > 1 threads, and it's prone to cause
> deadlocks on some others where it works.

Since 'fork' is required to be async-signal safe, the latter shouldn't
happen on a UNIX(*)-system. Independently of this, the people working
'pthreads' have troubles imagining that both multiprocessing and
multithreading could be useful and (apparently) refuse to define
sensible semantics for that, which is arguably somewhat difficult in
the absence of any information about the behaviour of the threads of
an application. Real-world problems aren't usually that general and
forking from multithreaded processes is completely possible (and
useful).

[...]

> So, we must use posix_spawn() (an equivalent of fork() and exec*()) if we
> want portability and threads, and fork() is now mostly useless.

That some set of people cannot get their act together in this respect,
not the least because they probably don't really want to, has no wider
ranging consequences than exactly this.

Geoff Clare

unread,
Apr 17, 2009, 8:23:23 AM4/17/09
to
cinsk wrote:

> pthread_sigmask() is async-signal-safe function. Right?

That's an interesting question. POSIX doesn't include it in the
list of async-signal-safe functions, but it does say:

The function shall be equivalent to sigprocmask(), without the
restriction that the call be made in a single-threaded process.

Since sigprocmask() is async-signal-safe, this equivalence implies
that pthread_sigmask() is also async-signal-safe.

I will report it as a defect.

--
Geoff Clare <net...@gclare.org.uk>

George Peter Staplin

unread,
Apr 17, 2009, 1:41:46 PM4/17/09
to
Rainer Weikusat wrote:

> George Peter Staplin <geor...@xmission.com> writes:
>>> Is there any signal-safe pthread function?
>>>
>>> I searched SUS (POSIX) specification and I found no pthread_* function
>>> in what they call async-signal-safe functions.
>>>
>>> I searched this group and found that pthread_mutex_lock() should not
>>> be used in a signal handler. What about other pthread_* functions?
>
> [...]
>
>> My understanding is that pthread_mutex_lock() is very likely to
>> deadlock in a signal handler.
>
> However pthread_mutex_lock might be implemented, it is inconceivable
> that it would 'likely deadlock' when called from a signal handler in
> absence of deliberate sabotage. It is not async-signal safe, hence,
> the behaviour is undefined if a signal handler whose execution
> interrupted another unsafe function calls it.


This is actually more *likely* on more than a few systems. I quote from the
Ubuntu manual page:

"ASYNC-SIGNAL SAFETY
The mutex functions are not async-signal safe. What this means is
that they should not be called from a signal handler. In particular,
calling !pthread_mutex_lock! or !pthread_mutex_unlock! from a signal
handler may deadlock the calling thread."

It's due to the way that mutex are usually implemented, and IIRC the signal
may introduce a race in some mutex state.

>> POSIX really in my opinion, did not fully solve the thread problem,
>> and I have doubts that they ever fully will.
>
> There are still people arguing that 'threads' as such need to be
> uninvented because they (the people themselves) have trouble
> understanding systems which consist of multiple, independently moving
> parts (This is a common deficiency among a lot of people, but
> typically, only professors of mathematics demand that everything else
> needs to be adapated to them :->. I would second this, provided it can
> be ascertained that none of them ever drives a car :->>).

I think we need thread-like patterns. I don't think we need the SRC-style
model of threads that most people use, and I certainly would prefer to have
a fork() that works with pthreads.



>> A related async-safety issue is that fork() is useless with some
>> systems when there are > 1 threads, and it's prone to cause
>> deadlocks on some others where it works.
>
> Since 'fork' is required to be async-signal safe, the latter shouldn't
> happen on a UNIX(*)-system. Independently of this, the people working
> 'pthreads' have troubles imagining that both multiprocessing and
> multithreading could be useful and (apparently) refuse to define
> sensible semantics for that, which is arguably somewhat difficult in
> the absence of any information about the behaviour of the threads of
> an application. Real-world problems aren't usually that general and
> forking from multithreaded processes is completely possible (and
> useful).

Actually, you're wrong. Several systems have a fork() that returns ENOSYS
when used with more than 1 thread. QNX being one of them. A user is
supposed to use spawn() or posix_spawn().

http://www.qnx.com/developers/docs/6.3.0SP3/neutrino/lib_ref/f/fork.html

From that manual:
"Caveats:

Currently, fork() is supported only in single-threaded applications. If you
create a thread and then call fork(), the function returns -1 and sets
errno to ENOSYS."



> [...]
>
>> So, we must use posix_spawn() (an equivalent of fork() and exec*()) if we
>> want portability and threads, and fork() is now mostly useless.
>
> That some set of people cannot get their act together in this respect,
> not the least because they probably don't really want to, has no wider
> ranging consequences than exactly this.

You're wrong on at least some systems. Good luck using fork with a threaded
library. You won't be able to effectively fork(). I suspect you have
never tried, because you would know it usually breaks, depending on the
code paths in question, and the state of the mutex and threads before the
fork() occurred. Only one thread forks, and you generally can't recreate
the entire state of the program, but there is an exception.
Solaris/OpenSolaris has a fork_all() system call that does allow this, but
not with POSIX threads. If you can fork() it's generally advised (even by
some POSIX committee members) to use exec*() immediately following the
successful child path.

See: http://docs.sun.com/app/docs/doc/805-5080/6j4q7emi4?a=view

-George

Rainer Weikusat

unread,
Apr 17, 2009, 2:11:49 PM4/17/09
to
George Peter Staplin <geor...@xmission.com> writes:
> Rainer Weikusat wrote:
>> George Peter Staplin <geor...@xmission.com> writes:
>>>> Is there any signal-safe pthread function?
>>>>
>>>> I searched SUS (POSIX) specification and I found no pthread_* function
>>>> in what they call async-signal-safe functions.
>>>>
>>>> I searched this group and found that pthread_mutex_lock() should not
>>>> be used in a signal handler. What about other pthread_* functions?
>>
>> [...]
>>
>>> My understanding is that pthread_mutex_lock() is very likely to
>>> deadlock in a signal handler.
>>
>> However pthread_mutex_lock might be implemented, it is inconceivable
>> that it would 'likely deadlock' when called from a signal handler in
>> absence of deliberate sabotage. It is not async-signal safe, hence,
>> the behaviour is undefined if a signal handler whose execution
>> interrupted another unsafe function calls it.
>
> This is actually more *likely* on more than a few systems. I quote from the
> Ubuntu manual page:
>
> "ASYNC-SIGNAL SAFETY
> The mutex functions are not async-signal safe. What this means is
> that they should not be called from a signal handler. In particular,
> calling !pthread_mutex_lock! or !pthread_mutex_unlock! from a signal
> handler may deadlock the calling thread."

That's hogwash. Calling a UNIX(*)-API function which is not defined as
being async-signal safe from a signal handler whose execution
interrupted another unsafe function is 'undefined behaviour'. But it
is undefined behaviour because the other functions was interrupted,
not because the call itself was done in the signal handler. You are
quoting the LinuxThreads-manpage for pthread_mutex_lock and this is
not an authoritative source of information, especially taking into
account that LinuxThreads itself is long obsolete.

> It's due to the way that mutex are usually implemented, and IIRC the
> signal may introduce a race in some mutex state.

It is conceivable that the LinuxThreads-implementation of 'mutexes' is
buggy (as in 'not standards-compliant') in this respect (I don't know
and I don't feel like checking the sources either). But this is a
comp.unix.programmer-question and not a
alt.stories.about.bugs.in.obsolete.Linux.libraries one.

[...]


>>> systems when there are > 1 threads, and it's prone to cause
>>> deadlocks on some others where it works.
>>
>> Since 'fork' is required to be async-signal safe, the latter shouldn't
>> happen on a UNIX(*)-system. Independently of this, the people working
>> 'pthreads' have troubles imagining that both multiprocessing and
>> multithreading could be useful and (apparently) refuse to define
>> sensible semantics for that, which is arguably somewhat difficult in
>> the absence of any information about the behaviour of the threads of
>> an application. Real-world problems aren't usually that general and
>> forking from multithreaded processes is completely possible (and
>> useful).
>
> Actually, you're wrong.

No, I am not. 'fork' is required to be async-signal safe by the
UNIX(*)-standard.

> Several systems have a fork() that returns ENOSYS
> when used with more than 1 thread. QNX being one of them.

That's a much weaker claim than the one you originally made ("prone to
cause deadlocks on 'other systems') and I would wager a bet that none
of these 'other systems' actually qualifies as UNIX(*) or at least as
'seriously trying to be compatible with UNIX(*)' (feel free prove me
wrong by giving examples).

[...]

>>> So, we must use posix_spawn() (an equivalent of fork() and exec*()) if we
>>> want portability and threads, and fork() is now mostly useless.
>>
>> That some set of people cannot get their act together in this respect,
>> not the least because they probably don't really want to, has no wider
>> ranging consequences than exactly this.
>
> You're wrong on at least some systems. Good luck using fork with a threaded
> library. You won't be able to effectively fork(). I suspect you have
> never tried, because you would know it usually breaks,

I suspect that you are talking out of your ass.

Rainer Weikusat

unread,
Apr 17, 2009, 2:16:40 PM4/17/09
to
George Peter Staplin <geor...@xmission.com> writes:
> Rainer Weikusat wrote:
>> George Peter Staplin <geor...@xmission.com> writes:
>>>> Is there any signal-safe pthread function?
>>>>
>>>> I searched SUS (POSIX) specification and I found no pthread_* function
>>>> in what they call async-signal-safe functions.
>>>>
>>>> I searched this group and found that pthread_mutex_lock() should not
>>>> be used in a signal handler. What about other pthread_* functions?
>>
>> [...]
>>
>>> My understanding is that pthread_mutex_lock() is very likely to
>>> deadlock in a signal handler.
>>
>> However pthread_mutex_lock might be implemented, it is inconceivable
>> that it would 'likely deadlock' when called from a signal handler in
>> absence of deliberate sabotage. It is not async-signal safe, hence,
>> the behaviour is undefined if a signal handler whose execution
>> interrupted another unsafe function calls it.
>
> This is actually more *likely* on more than a few systems. I quote from the
> Ubuntu manual page:
>
> "ASYNC-SIGNAL SAFETY
> The mutex functions are not async-signal safe. What this means is
> that they should not be called from a signal handler. In particular,
> calling !pthread_mutex_lock! or !pthread_mutex_unlock! from a signal
> handler may deadlock the calling thread."

That's hogwash. Calling a UNIX(*)-API function which is not defined as


being async-signal safe from a signal handler whose execution
interrupted another unsafe function is 'undefined behaviour'. But it
is undefined behaviour because the other functions was interrupted,
not because the call itself was done in the signal handler. You are
quoting the LinuxThreads-manpage for pthread_mutex_lock and this is
not an authoritative source of information, especially taking into
account that LinuxThreads itself is long obsolete.

> It's due to the way that mutex are usually implemented, and IIRC the


> signal may introduce a race in some mutex state.

It is conceivable that the LinuxThreads-implementation of 'mutexes' is


buggy (as in 'not standards-compliant') in this respect (I don't know
and I don't feel like checking the sources either). But this is a
comp.unix.programmer-question and not a
alt.stories.about.bugs.in.obsolete.Linux.libraries one.

[...]


>>> systems when there are > 1 threads, and it's prone to cause
>>> deadlocks on some others where it works.
>>
>> Since 'fork' is required to be async-signal safe, the latter shouldn't
>> happen on a UNIX(*)-system. Independently of this, the people working
>> 'pthreads' have troubles imagining that both multiprocessing and
>> multithreading could be useful and (apparently) refuse to define
>> sensible semantics for that, which is arguably somewhat difficult in
>> the absence of any information about the behaviour of the threads of
>> an application. Real-world problems aren't usually that general and
>> forking from multithreaded processes is completely possible (and
>> useful).
>
> Actually, you're wrong.

No, I am not. 'fork' is required to be async-signal safe by the
UNIX(*)-standard.

> Several systems have a fork() that returns ENOSYS
> when used with more than 1 thread. QNX being one of them.

That's a much weaker claim than the one you originally made ("prone to


cause deadlocks on 'other systems') and I would wager a bet that none
of these 'other systems' actually qualifies as UNIX(*) or at least as
'seriously trying to be compatible with UNIX(*)' (feel free prove me
wrong by giving examples).

[...]

>>> So, we must use posix_spawn() (an equivalent of fork() and exec*()) if we
>>> want portability and threads, and fork() is now mostly useless.
>>
>> That some set of people cannot get their act together in this respect,
>> not the least because they probably don't really want to, has no wider
>> ranging consequences than exactly this.
>
> You're wrong on at least some systems. Good luck using fork with a threaded
> library. You won't be able to effectively fork(). I suspect you have
> never tried, because you would know it usually breaks,

Basically, what you write above is: "I suspect that you [me] are lying,
because you wrote something I don't want to believe in.".

This, in turn, leads me into a (strong) suspicion, namely, that your are
making vague claims and personal attacks for the want of anything else
which would support your position.

George Peter Staplin

unread,
Apr 17, 2009, 3:05:06 PM4/17/09
to
Rainer Weikusat wrote:

> George Peter Staplin <geor...@xmission.com> writes:

>> Rainer Weikusat wrote:
>>>> So, we must use posix_spawn() (an equivalent of fork() and exec*()) if
>>>> we want portability and threads, and fork() is now mostly useless.
>>>
>>> That some set of people cannot get their act together in this respect,
>>> not the least because they probably don't really want to, has no wider
>>> ranging consequences than exactly this.
>>
>> You're wrong on at least some systems. Good luck using fork with a
>> threaded
>> library. You won't be able to effectively fork(). I suspect you have
>> never tried, because you would know it usually breaks,
>
> Basically, what you write above is: "I suspect that you [me] are lying,
> because you wrote something I don't want to believe in.".
>
> This, in turn, leads me into a (strong) suspicion, namely, that your are
> making vague claims and personal attacks for the want of anything else
> which would support your position.

Look, I gave you proof if you had read the links I quoted. If you don't
want to read it, and choose to snip that, then by all means choose what you
want to believe.

If QNX and Mac OS X aren't a "UNIX" to you, then I don't personally care how
you define "UNIX," because you are incorrect.

See Caveats:
http://www.qnx.com/developers/docs/6.3.0SP3/neutrino/lib_ref/f/fork.html

See Caveats:
http://developer.apple.com/documentation/Darwin/Reference/Manpages/man2/fork.2.html

-George

Chris Friesen

unread,
Apr 17, 2009, 3:15:13 PM4/17/09
to
George Peter Staplin wrote:

> Rainer Weikusat wrote:
>> However pthread_mutex_lock might be implemented, it is inconceivable
>> that it would 'likely deadlock' when called from a signal handler in
>> absence of deliberate sabotage. It is not async-signal safe, hence,
>> the behaviour is undefined if a signal handler whose execution
>> interrupted another unsafe function calls it.
>
>
> This is actually more *likely* on more than a few systems. I quote from the
> Ubuntu manual page:
>
> "ASYNC-SIGNAL SAFETY
> The mutex functions are not async-signal safe. What this means is
> that they should not be called from a signal handler. In particular,
> calling !pthread_mutex_lock! or !pthread_mutex_unlock! from a signal
> handler may deadlock the calling thread."
>
> It's due to the way that mutex are usually implemented, and IIRC the signal
> may introduce a race in some mutex state.

Many (if not all) of the functions that are not async-signal safe may be
called safely from signal handlers if the application ensures that
signals are blocked while the function is called in the main part of the
application.

> Actually, you're wrong. Several systems have a fork() that returns ENOSYS
> when used with more than 1 thread. QNX being one of them. A user is
> supposed to use spawn() or posix_spawn().

SuSv3 specifically allows multithreaded apps to fork(). Therefore, by
definition a system that doesn't allow this is not a fully compliant
implementation of UNIX.

From the fork() docs:

"A process shall be created with a single thread. If a multi-threaded
process calls fork(), the new process shall contain a replica of the
calling thread and its entire address space, possibly including the
states of mutexes and other resources. Consequently, to avoid errors,
the child process may only execute async-signal-safe operations until
such time as one of the exec functions is called. Fork handlers may be
established by means of the pthread_atfork() function in order to
maintain application invariants across fork() calls.

When the application calls fork() from a signal handler and any of the
fork handlers registered by pthread_atfork() calls a function that is
not asynch-signal-safe, the behavior is undefined."


Chris

George Peter Staplin

unread,
Apr 17, 2009, 3:31:41 PM4/17/09
to
Chris Friesen wrote:

So what good is a fork() if the mutex state can't be changed with
pthread_atfork() handlers? If you study the comp.programming.threads
archives you will find several messages by David Butenhof (a member of the
POSIX threads committee).

"The real answer is that pthread_atfork() is a completely useless and stupid
mechanism that was a well intentioned but ultimately pointless attempt to
carve a "back door" solution out of an inherently insoluable design
conflict." -- David Butenhof

That's from:
http://groups.google.com/group/comp.programming.threads/msg/3a43122820983fde

So, simply put (if you read that article): POSIX threads and fork() don't
mix well, unless you use exec*() immediately in the child, and even then
there are problems associated with some systems returning ENOSYS from
fork(). I stand by my statement that fork() is now mostly useless when
libraries and system applications may or may not use POSIX threads.

-George

Chris Friesen

unread,
Apr 17, 2009, 4:11:10 PM4/17/09
to
George Peter Staplin wrote:

> So, simply put (if you read that article): POSIX threads and fork() don't
> mix well, unless you use exec*() immediately in the child, and even then
> there are problems associated with some systems returning ENOSYS from
> fork().

I stand by my statement that such systems are not UNIX. :)

If you have to develop for those systems, then yes there is a problem.

> I stand by my statement that fork() is now mostly useless when
> libraries and system applications may or may not use POSIX threads.

Arguably, most libraries should not spawn additional threads. It's rude
(not to mention unsafe) to invisibly convert a single-threaded app to a
multithreaded one.

The obvious exception to this is where the library is really an
application framework, and is documented to be multithreaded.

Chris

George Peter Staplin

unread,
Apr 17, 2009, 4:24:13 PM4/17/09
to
Chris Friesen wrote:

> George Peter Staplin wrote:
>
>> So, simply put (if you read that article): POSIX threads and fork() don't
>> mix well, unless you use exec*() immediately in the child, and even then
>> there are problems associated with some systems returning ENOSYS from
>> fork().
>
> I stand by my statement that such systems are not UNIX. :)
>
> If you have to develop for those systems, then yes there is a problem.
>
> > I stand by my statement that fork() is now mostly useless when
>> libraries and system applications may or may not use POSIX threads.
>
> Arguably, most libraries should not spawn additional threads. It's rude
> (not to mention unsafe) to invisibly convert a single-threaded app to a
> multithreaded one.

I agree. Unfortunately some audio libraries do this, and a few other
libraries I have come across. It makes life more difficult, and has
prevented me from using some code I wish I could have in some cases, so I
ended up reinventing the wheels a bit more.

I have also come to the conclusion after working on multithreaded problems
for years, and working with process-based solutions that I prefer processes
communicating with pipes to the DEC/SRC/POSIX-style thread model, even with
the complexity of shared memory solutions that may be needed in some cases
for performance. I mostly work with graphics though, so my needs may not
be yours.

-George

Mark Wooding

unread,
Apr 18, 2009, 10:08:39 AM4/18/09
to
George Peter Staplin <geor...@xmission.com> writes:

> Actually, you're wrong. Several systems have a fork() that returns
> ENOSYS when used with more than 1 thread. QNX being one of them. A
> user is supposed to use spawn() or posix_spawn().

Fortunately, no POSIX system does this (IEEE 1003.1--2001):

: * A process shall be created with a single thread. If a multi-
: threaded process calls fork(), the new process shall contain a


: replica of the calling thread and its entire address space,
: possibly including the states of mutexes and other resources.

-- [mdw]

Chris Friesen

unread,
Apr 20, 2009, 12:02:22 PM4/20/09
to
George Peter Staplin wrote:

> I have also come to the conclusion after working on multithreaded problems
> for years, and working with process-based solutions that I prefer processes
> communicating with pipes to the DEC/SRC/POSIX-style thread model, even with
> the complexity of shared memory solutions that may be needed in some cases
> for performance. I mostly work with graphics though, so my needs may not
> be yours.

Actually, I agree with this. I view concurrent programming as a
continuum, with "one process forking another" at one end, and "full-on
threaded programming" at the other.

I do high-availability embedded telecoms stuff primarily and have gotten
a lot of mileage out of individual apps communicating via unix sockets
(and a multicast unix socket-like protocol that we created). Where
necessary for speed, they set up shared memory between processes.

My personal view is that threading is purely a performance
optimization--and on many unix systems the difference in context switch
times between threads and processes is limited to the time taken to
flush the tlb.

Chris

0 new messages