Re: Thread-safe fuctions

From: subnet (sunglo_at_katamail.com)
Date: 03/26/05

  • Next message: Måns Rullgård: "Re: Thread-safe fuctions"
    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!


  • Next message: Måns Rullgård: "Re: Thread-safe fuctions"

    Relevant Pages

    • Re: Thread-safety and Singleton methods
      ... Why wouldn't static methods be thread-safe? ... instance of the singleton class) then of course if you change it once it'll ... > Parameters are passed to a method using a stack. ...
      (microsoft.public.dotnet.framework.aspnet)
    • Re: Stack and Thread Safety
      ... Stack could have thread unsafe parts in it. ... It's worth pointing out here that "thread-safe" is a rather vague term ... set of tree push operations are atomic. ...
      (comp.lang.java.help)
    • Thread-safety and Singleton methods
      ... read many posts on this topic but not clear about this and hence I am posting ... public methods in that class be thread-safe? ... they say that singleton class methods are thread-safe...I request you to ... Parameters are passed to a method using a stack. ...
      (microsoft.public.dotnet.framework.aspnet)
    • Re: Reentrancy problem in STA
      ... There are two approaches - rewrite your code to be reentrant, ... or rewrite it to be thread-safe ... and switch to MTA service (which makes much more sense for ...
      (microsoft.public.vc.atl)
    • Re: Reentrant functions and memory allocation
      ... independent way to write a reentrant function that allocate dynamic ... is it safe to use malloc() or freein a ... thread-safe function? ... know about threads but does know a little about reentrancy, and malloc/realloc/free are not required to be reentrant. ...
      (comp.lang.c)