Почему pthread_mutex_lock всегда возвращает 0 (но без ошибок), когда программа не связана с библиотекой pthreads?

Недавно я наткнулся на то, что я считаю довольно странным поведением библиотеки pthreads (или, по крайней мере, ее реализацией в Linux Mint 16, Ubuntu EGLIBC 2.17-93ubuntu4, NPTL 2.17, gcc Ubuntu/Linaro 4.8.1-10ubuntu9).

При компиляции программы pthreads я случайно забыл связать ее с библиотекой pthreads (т.е. я забыл добавить флаг -lpthread в командную строку gcc). Однако я скомпилировал программу со всеми включенными предупреждениями (-Wall) и не получил абсолютно никаких предупреждений или ошибок. Когда я запустил программу, подумал, что кажется, что блокировки просто не работают. Мне потребовалось немного времени, чтобы понять, но в конце концов я обнаружил, что, несмотря на то, что все вызовы pthread_mutex_lock возвращали 0 (успех), блокировки не устанавливались (т.е., например, два последовательных вызова pthread_mutex_lock для одной блокировки не будет приостанавливать исполнение).

Вот доказательство концепции кода, который я использовал для тестирования и воспроизведения поведения:

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;

}

Если я скомпилирую его без флага -lpthread, я не получу ошибок или предупреждений, и когда я его запускаю, он просто работает нормально и завершает выполнение.

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

Если я скомпилирую его с флагом -lpthread, я также не получу никаких ошибок или предупреждений, но когда я его запускаю, он просто зависает (при втором вызове pthread_mutex_lock) - что должно быть ожидаемым поведением.

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

Кто-нибудь может объяснить, почему, когда флаг -lpthread опущен (и, таким образом, программа не связана с библиотекой pthreads), компилятор не показывает ошибок или предупреждений, а также не показывает программу во время ее выполнения, но pthread_mutex_lock просто возвращает 0 и не возвращает держать замок?

Заранее спасибо за любые подсказки, которые вы можете предоставить.

1 ответ

Решение

Это всего лишь предположение, так как я не смотрел на код, но я считаю, что идея состоит в том, чтобы позволить библиотечному коду (системному или стороннему) использовать pthread_mutex_lock в не многопоточных программах без каких-либо накладных расходов и без необходимости libpthread быть связанным. Поскольку такие программы не имеют нескольких потоков, нет необходимости в каком-либо взаимном исключении, и "фиктивная" реализация мьютексов не вызывает никаких проблем, если только мьютексы не используются менее общепринятым образом (например, с использованием pthread_mutex_trylock наблюдать, не заблокирован ли мьютекс).

Если мои подозрения верны, это, вероятно, "меньшее из двух зол". С одной стороны, действительно неправильно иметь нерабочие версии pthread_mutex_lock которые молча терпят неудачу, когда вы забыли связать libpthread, Это может особенно повлиять на программы, использующие разделяемые процессами мьютексы, которым не нужно создавать потоки, чтобы mmap и использовать в качестве разделяемого процессом мьютекса другую созданную программу, где вы не заметите других ошибок компоновки из-за отсутствия pthread_createи т. д. С другой стороны, имея pthread_mutex_lock символ доступен без libpthread отговаривает авторов сторонних библиотек делать "поддержку потоков" необязательной функцией (чтобы избежать ссылки libpthread) и, возможно, требует наличия функции "init threads", которая на самом деле не может быть безопасно вызвана в многопоточной программе (это отдельный вопрос, который мы могли бы обсудить по новому вопросу, если вам интересно). Такое поведение авторов библиотек было чрезвычайно распространенным (и в некоторой степени все еще существует) и делает многопоточное программирование гораздо более болезненным, чем следовало бы из-за необходимости бороться с библиотеками, которые не работают "из коробки" в многопоточных средах. Поэтому заставить людей прекратить делать это имеет большую ценность.

Действительно, мое подозрение подтверждается принятым ответом на этот вопрос:

Как создать библиотеку, которая использует мьютексы, только если pthread связан?

Кроме того, провал "фиктивной реализации" мьютексов не совсем молчит; ошибка возвращается. Вы просто не проверяете это.

Другие вопросы по тегам