Почему 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 связан?
Кроме того, провал "фиктивной реализации" мьютексов не совсем молчит; ошибка возвращается. Вы просто не проверяете это.