"3.407 Thread-Safe A thread-safe function can be safely invoked concurrently with other calls to the same function, or with calls to any other thread-safe functions, by multiple threads. Each function defined in the System Interfaces volume of POSIX.1-2017 is thread-safe unless explicitly stated otherwise. Examples are any 'pure' function, a function which holds a mutex locked while it is accessing static storage, or objects shared among threads."
Doesn't that indicate that a libc implementation is allowed to be written so that the execution of a non-thread-safe function that isn't mutex-protected may break the thread-safety of every allegedly thread-safe function concurrently executing?
It seems unlikely that the execution of the non-thread-safe mathematical function lgamma() would somehow interfere with the execution of a thread-safe totally unrelated function in another thread, but it appears to me that the Standard allows it, so that 'pure' functions can become thread-unsafe. Is this the intent?
More likely would be that mblen() could destroy the thread-safety of a concurrently executing mbrlen(). But that would severely restrict the utility of threads. It would mean that I can't add a new thread to an existing application without close inspection of the code because of this possibility of bleed through.
Or is this just poor wording in the Standard (it wouldn't be the first time)?
This is theoretical; I haven't tried to demonstrate this, and I hope I'm wrong
Question edited to add what's below:
I think I didn't ask this clearly enough. So I'll rephrase my question to use a specific example.
Suppose there are two threads concurrently executing the mbrlen() function, both with the ps arg set to not NULL. The Standard requires a conformant libc implementation to be written in such a way that neither function call interferes with that of the other thread.
Now suppose that the situation is changed so that one of the threads is using the mblen() function instead. This is the only difference from the above situation. May a libc implementation that is compliant with the Standard be written such that the mblen() call could cause the other thread's mbrlen() call to return the wrong result?
Answer "No" if the Standard prohibits a compliant implementation from having any possibility of such interference. If you answer no, please cite the text in the Standard that indicates such a prohibition.
Otherwise answer "Yes". But the implication of this answer is that no thread need be safe unless all threads are safe; no function call need be thread-safe unless all other concurrent function calls are thread-safe.
I need to emphasize that I'm not referring to how libc implementations actually work, but the legalese of the Standard. I have written code assuming that the answer is "No" and has millions of instances executing around the world in every instant of every day. Applications are free to add threads executing whatever they want, and we've had no reports of this kind of error. Maybe some heisenbugs are a result of this; maybe nobody adds interfering threads. But I do think this is pretty good evidence that libc applications don't take advantage of this loophole, if indeed it is a loophole.
No, it does not. It means calling two such functions from two threads at the same time breaks the thread safety of everything.
However there are a few exceptions.
chdir(),setenv(), andunsetenv()are super not-thread-safe and can cause problems for thread-safe functions.chdir(): most FS functions won't be happy with changing the current directory in the middle.setenv()andunsetenv():getenv()is listed as thread safe but isn't if one of these is being called from another thread.The standard appears to say something really dumb though: I don't see why you can't call
strtok()from one thread andlgamma()from another but it reads like you can't.I went back through the question and read up on
mblen()andmbrlen()more thoroughly. It's not as bad as it sounds.mbrlen()is definitely thread safe whenever its third argument is notNULL. It's a pretty good guess however thatmblen(s, n)is implemented asmbrlen(s, n, NULL)in older implementations and so the standard leaves open that possibility; but later on the documentation formbrlen()was updated to remove this case. (The modern definition reads "The system shall behave as though no [standard library] function calls mbrlen".)