Re: Thread-safe fuctions
From: subnet (sunglo_at_katamail.com)
Date: 03/26/05
- Previous message: Michael B Allen: "struct winsize on OSF1?"
- In reply to: Stephen: "Re: Thread-safe fuctions"
- Next in thread: Måns Rullgård: "Re: Thread-safe fuctions"
- Reply: Måns Rullgård: "Re: Thread-safe fuctions"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: 26 Mar 2005 10:46:01 -0800
Stephen wrote:
> I don't claim to offer a definitive answer, but a little
> Google research _seems_ to shows that reentrant is an older
> term and seems to be 1st applied to complete programs - i.e.,
> a program is reentrant if more than one user can run it
> without affecting the other(s). I think (IMHO) nowadays,
> the two terms are safely interchangeable. There might be an
> argument that "thread-safe" means (more of a) "parallel
> execution" model, and reentrant means able to be called
> "safely from itself" model.
That's the idea I tried to explain in my previous post.
Furthermore, I always have heard of "reentrant" as being a
stronger concept that just "thread-safe" (see my reply to Bjorn Reese).
> Note, that the scope of a reentrant function can extend
> beyond the function itself.
>
> Consider the 'strtok()' example. The function 'strtok()',
> even in a non-threaded application, is _not_ reentrant.
> Once you start a 'strtok()' function, you cannot start
> another 'strtok()' function until the 1st is completed.
> This is because 'strtok()' maintains internal state
> information used between successive calls to itself.
In a single-threaded environment, there's also no (easy)
way to force it to reenter. All you can do is call it many
times until it returns NULL. So its deficiencies really
show up only in a multi-threaded environment, where strtok_r()
must be used instead if defined behaviour is desired.
> Not necessarily. The _same_ thread can acquire the _same_
> mutex, if the programmer so desires. A recursive algorithm
> can be used in a threaded program and have its data
> protected by a mutex as needed (man 'pthread_mutex_lock()').
> The multiple locking/unlocking of the mutex simply adjusts a
> reference count for owner the mutex (the original locking thread).
Personally, I don't like recursive mutexes very much, but
nonetheless I must admit that there are situations where they
could be handy/useful/necessary.
Furthermore, I think that the term "recursive" is orthogonal to the
concept of "thread safety" (ie, the fact that a function is
recursive doesn't say anything about its suitability to be used in a
multi-threaded environment). If it does not modify global or static
data (or does so with the necessary protections), then it can be used
by many threads at once; otherwise it can't.
> It's been my experience that this is where most
> mis-understandings occur and I guess it can't be
> helped. The label REENTRANT/THREAD-SAFE doesn't
> apply to a function's instruction _code_ (unless we
> go back to assembler days when functions could
> modify themselves). The label applies to the
> changeable data (this does not apply to the stack
> because it's impossible for two simultaneous
> functions to occupy the same position on the stack)
> a function manages.
Ok, I agree, and probably I did not use the right words to
phrase my concepts.
When I talked about thread-safety and reentrancy, I was
referring to the safety of the (shared/global/static) data
manipulated by the function, and I did not mean to say anything
about the structure of the code.
If I ask "is the function foo() thread-safe" I mean: "if the
function foo() is executed by many threads at the same time, is
the static/global/shared data it manipulates behind the scene
left in a "safe" (ie, consistent) state"?
Sorry, I apologize if this was not clear enough from my previous
post.
Local stack data is safe by definition (I know that it's possible
for a stack to access another thread's stack, but I'm deliberately
ignoring these awkward techniques; in my opinion the program should
be designed in such a way that these tricks are not needed).
> For example, we know that the 'strcat()' function
> by itself is reentrant/thread-safe. However, if more
> than 1 thread is attempting a 'strcat()' to the
> _same_ memory location, the results are undefined
> unless that memory is protected against concurrent
> access through a mutex.
>
> Note, 'strcat()' is a trivial function. But replace
> it with 'snprintf()'. In my environment, 'snprintf()'
> is described as a safe in multi-threaded programs.
> But that only means that and internal data structures
> used by 'snprintf()' are protected inside the function
> itself. Again, if more than 1 thread is 'snprintf()'ing
> to the same memory location, the results are undefined.
As I said before, I completely agree with this. We can call
it a "thread-safe" function that can be defeated by
malicious/bugged programs.
In other words, it's thread-safe _under certain conditions_.
These conditions I took for granted in my previous post,
since I think it's not the library function's job to protect
against program bugs and, if the programmer really wants to
deliberately use strcat() to the same memory address from
more than one thread, then I suppose he should know what he's
doing (and thus take the necessary precautions himself). The
library functions can not (and, imho, should not) help with
this, and correctly ignore whether the supplied data is
protected or not. If a man page says that the function foo()
is thread-safe, this surely does not mean that it also
protects user-supplied data, data that might happen to point
to some shared unprotected memory area.
otoh, if the man page says that foo() is not thread-safe,
we can be sure that it's not protecting it's *internal*
static data either (for example because it's not possible or
for whatever reason).
So, my point was a little bit more specific. What I was
referring to when I talked about safety/reentrancy was the
static data that the library functions use internally (for
example, some internal static data used by malloc(),
snprintf() and other similar data structures invisible to the
programmer), and I was wondering about the consequences of
concurrent execution on these internal structures.
Now, as you and some other pointed out, I know that, unless
otherwise noted, and unless the caller is forcing the function
to operate on unprotected data (but this is a caller's problem,
and the function knows nothing about it), the library functions
are thread-safe.
Again, many thanks for your patience and help!
- Previous message: Michael B Allen: "struct winsize on OSF1?"
- In reply to: Stephen: "Re: Thread-safe fuctions"
- Next in thread: Måns Rullgård: "Re: Thread-safe fuctions"
- Reply: Måns Rullgård: "Re: Thread-safe fuctions"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|