C语言 为什么当程序没有链接到pthreads库时,pthread_mutex_lock总是返回0(但没有错误)



我最近无意中发现了我认为相当奇怪的pthreads库行为(或者至少是它在Linux Mint 16, Ubuntu EGLIBC 2.17-93ubuntu4, NPTL 2.17, gcc Ubuntu/Linaro 4.8.1-10ubuntu9中的实现)。

在编译pthreads程序时,我不小心忘记将它与pthreads库链接(即,我忘记在gcc命令行中添加-lpthread标志)。但是,我在编译程序时启用了所有警告(-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并且不持有锁?

提前感谢您提供的线索

这只是一个猜测,因为我没有看过代码,但我相信这个想法是允许库代码(系统级或第三方)在非多线程程序中使用pthread_mutex_lock,而不会产生任何开销,也不需要链接libpthread。因为这样的程序没有多线程,所以不需要任何互斥,并且互斥的"虚拟"实现不会引起任何问题,除非互斥以一种非常规的方式使用(例如使用pthread_mutex_trylock观察互斥是否已经锁定)。

如果我的怀疑是正确的,这可能是"两害相权取其轻"。一方面,当您忘记链接libpthread时,pthread_mutex_lock的非工作版本静默失败是错误的。这可能会特别影响使用进程共享互斥锁的程序,这些程序不需要为mmap创建线程,并使用另一个程序创建的进程共享互斥锁,这样您就不会观察到由于缺少pthread_create等导致的其他链接错误。另一方面,在没有libpthread的情况下使用pthread_mutex_lock符号会阻碍第三方库作者将"线程支持"作为可选功能(以避免必须链接libpthread),并且可能需要在多线程程序中实际上不能安全调用的"init threads"函数(这是一个单独的问题,如果您感兴趣,我们可以在新问题上讨论)。库作者的这种行为曾经非常普遍(在某种程度上仍然如此),并且使多线程编程比应该的更加痛苦,因为必须与不能在多线程环境中"开箱即用"的库作斗争。因此,让人们停止这样做是很有价值的。

事实上,我的怀疑得到了这个问题的公认答案的支持:

如何创建一个库,使用互斥锁只有如果pthread是链接?

此外,互斥锁的"虚拟实现"的失败并不是完全无声的;返回一个错误。你只是没有检查它。

相关内容

  • 没有找到相关文章

最新更新