Search code examples
clinuxgccpthreadsnptl

Why does pthread_mutex_lock always return 0 (but no errors) when a program is not linked to the pthreads library?


I recently stumbled upon what I thought was quite a weird behavior of the pthreads library (or at least its implementation in Linux Mint 16, Ubuntu EGLIBC 2.17-93ubuntu4, NPTL 2.17, gcc Ubuntu/Linaro 4.8.1-10ubuntu9 ).

When compiling a pthreads program, I accidentally forgot to link it with the pthreads library (i.e., I forgot to add the -lpthread flag to the gcc command line). I did, however, compile the program with all warnings enabled (-Wall) and received absolutely no warnings or errors. When I ran the program, thought, it appeared as if the locks were simply not working. It took me a little while to figure out, but eventually I found out that despite all the calls to pthread_mutex_lock were returning 0 (success), the locks were not being set (i.e., for example, two sequential calls to pthread_mutex_lock on the same lock would not suspend execution).

Here's a proof of concept code that I used to test and reproduce the behavior:

int main( int argc, char **argv ) {

  pthread_mutex_t mutex;

  pthread_mutex_init( &mutex, NULL );
  pthread_mutex_lock( &mutex );
  pthread_mutex_lock( &mutex );
  pthread_mutex_unlock( &mutex );

  return 0;

}

If I compile it without the -lpthread flag, I get no errors or warnings and when I run it, it simple runs normally and finishes executing.

me@mybox /tmp $ gcc -Wall mutex.c -o mutex
me@mybox /tmp $ ./mutex
me@mybox /tmp $

If I compile it with the -lpthread flag, I also do not get any errors or warnings, but when I run it, it simply hangs (on the second call to pthread_mutex_lock) - which should be the expected behavior.

me@mybox /tmp $ gcc -Wall mutex.c -o mutex -lpthread
me@mybox /tmp $ ./mutex
^C
me@mybox /tmp $ 

Can anybody explain why, when the -lpthread flag is omitted (and thus the program is not linked to the pthreads library), the compiler shows no error or warnings, nor does the program during its execution, but pthread_mutex_lock simply returns 0 and does not hold the lock?

Thank you in advance for any clues you can provide.


Solution

  • This is just a guess since I haven't looked at the code, but I believe the idea is to allow library code (either system level or third-party) to use pthread_mutex_lock in non-multi-threaded programs without incurring any overhead and without requiring libpthread to be linked. Since such programs do not have multiple threads, there is no need for any mutual exclusion, and the "dummy" implementation of mutexes does not cause any problems unless mutexes are being used in a less-conventional manner (e.g. using pthread_mutex_trylock to observe whether the mutex is already locked).

    If my suspicions are correct, this is probably a "lesser of two evils". On the one hand, it's really wrong to have non-working versions of pthread_mutex_lock that silently fail when you forget to link libpthread. This could especially affect programs using process-shared mutexes which don't need to create threads in order to mmap and use as process-shared mutex another program created, where you would not observe other linking errors from missing pthread_create, etc. On the other hand, having a pthread_mutex_lock symbol available without libpthread discourages third-party library authors from making "thread support" an optional feature (to avoid having to link libpthread) and possibly requiring an "init threads" function which cannot actually be called safely in a multi-threaded program (this is a separate matter which we could discuss on a new question if you're interested). Such behavior by library authors used to be extremely common (and to some extent, still is) and makes multi-threaded programming much more painful than it should be due to having to fight with libraries that don't work "out of the box" in multi-threaded environments. So getting people to stop doing that has a lot of value.

    Indeed, my suspicion is supported by the accepted answer to this question:

    How to create a library which uses mutexes only if pthread is linked?

    Further, the failure of the "dummy implementation" of mutexes is not entirely silent; an error is returned. You're just not checking for it.