c++ - 从静态构造函数代码调用时 pthread 库失败

标签 c++ c gcc pthreads glib

我有一个包含 GLib library 的 C++ 共享库对象。

当我创建一个带有main() 函数的最小测试程序,并链接到共享库时,该程序在运行时立即中止,并显示以下 GLib错误信息:

GLib (gthread-posix.c): Unexpected error from C library during 'pthread_cond_init': Invalid argument.  Aborting.

因为我的主函数是空的,错误一定是在某个地方的某个预主初始化函数中发生的。因此,使用 GDB 我发现 GLib 有一个静态初始化构造函数(在 glib-init.c 中),它在运行时调用 main() 之前。在该初始化函数中,它调用了 pthread_cond_init,但神秘地失败了。

这是完整的回溯:

(gdb) run
Starting program: ~/example
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x2aaaaaaab000
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
GLib (gthread-posix.c): Unexpected error from C library during 'pthread_cond_init': Invalid argument.  Aborting.

Program received signal SIGABRT, Aborted.
0x0000003891830265 in raise () from /lib64/libc.so.6
(gdb) bt
#0  0x0000003891830265 in raise () from /lib64/libc.so.6
#1  0x0000003891831d10 in abort () from /lib64/libc.so.6
#2  0x00002aaaab9aed32 in g_thread_abort (status=22,
    function=0x2aaaabcbdd2b "pthread_cond_init")
    at ~/libs/glib/gthread-posix.c:75
#3  0x00002aaaab9af349 in g_cond_impl_new ()
    at ~/libs/glib/gthread-posix.c:656
#4  0x00002aaaab9af39b in g_cond_get_impl (
    cond=0x2aaaac15f690 <g_once_cond>)
    at ~/libs/glib/gthread-posix.c:677
#5  0x00002aaaab9af4b2 in g_cond_broadcast (
    cond=0x2aaaac15f690 <g_once_cond>)
    at ~/libs/glib/gthread-posix.c:792
#6  0x00002aaaab9ab529 in g_once_init_leave (
    location=0x2aaaac160510 <g_define_type_id__volatile.11714>,
    result=6524000) at ~/libs/glib/gthread.c:682
#7  0x00002aaaaba34a2f in g_value_array_get_type ()
    at ~/libs/gobject/gboxed.c:132
#8  0x00002aaaaba41b28 in _g_param_spec_types_init ()
    at ~/libs/gobject/gparamspecs.c:1511
#9  0x00002aaaaba30c72 in gobject_init_ctor ()
    at ~/libs/gobject/gtype.c:4391
#10 0x00002aaaabb2bc36 in __do_global_ctors_aux ()
   from ./MYLIB.so
#11 0x00002aaaaad368eb in _init () from ./MYLIB.so
#12 0x00002aaab0180e60 in ?? ()
#13 0x000000389140d4ab in call_init ()
  from /lib64/ld-linux-x86-64.so.2
#14 0x000000389140d5b5 in _dl_init_internal ()
   from /lib64/ld-linux-x86-64.so.2
#15 0x0000003891400aaa in _dl_start_user ()
   from /lib64/ld-linux-x86-64.so.2
#16 0x0000000000000001 in ?? ()
#17 0x00007fffffffe6de in ?? ()
#18 0x0000000000000000 in ?? ()

所以,我的第一个想法可能是 .so 文件没有正确链接到 pthread 库。因此,我使用 ldd 实用程序来检查它是如何链接到 pthread 的:

$ ldd MYLIB.so
        linux-vdso.so.1 =>  (0x00007fff56ed1000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00002b8a747bf000)
        librt.so.1 => /lib64/librt.so.1 (0x00002b8a749db000)
        libpng12.so.0 => /usr/lib64/libpng12.so.0 (0x00002b8a74be5000)
        libfontconfig.so.1 => /usr/lib64/libfontconfig.so.1 (0x00002b8a74e09000)
        libz.so.1 => /lib64/libz.so.1 (0x00002b8a7503d000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00002b8a75252000)
        libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00002b8a75456000)
        libm.so.6 => /lib64/libm.so.6 (0x00002b8a75756000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00002b8a759da000)
        libc.so.6 => /lib64/libc.so.6 (0x00002b8a75be8000)
        /lib64/ld-linux-x86-64.so.2 (0x0000003891400000)
        libfreetype.so.6 => /usr/lib64/libfreetype.so.6 (0x00002b8a75f41000)
        libexpat.so.0 => /lib64/libexpat.so.0 (0x00002b8a761c6000)

因此,它通过 /usr/lib64/pthread.so.0 与 libpthread 正确链接

然后我查看了在 pthread_cond_init 上失败的 GLib 源代码。这非常简单。为了清楚起见,我删除了一些 #ifdef 语句:

  pthread_condattr_t attr;
  pthread_cond_t *cond;
  gint status;
  pthread_condattr_init (&attr);

  cond = malloc (sizeof (pthread_cond_t));
  if G_UNLIKELY (cond == NULL)
    g_thread_abort (errno, "malloc");

  if G_UNLIKELY ((status = pthread_cond_init (cond, &attr)) != 0) <--- this fails
    g_thread_abort (status, "pthread_cond_init");

所以那里看起来没有任何问题,我怀疑 GLib 是否会出现任何像这样的明显错误,考虑到它在许多主要 Linux 代码库中被广泛使用。

所以,在这一点上,我没有想法。这个问题有哪些可能和/或可能的原因?这是否可能是一个初始化顺序问题,pthread lib 需要在 GLib 使用它之前执行一些静态初始化?

最佳答案

glibc-2.5 中有两个版本的pthread_cond_init。旧的,大概是用过的,有评论说

neither clocks other than CLOCK_REALTIME

都支持,可以返回EINVAL

在线642 gthread-posix.c 的调用

pthread_condattr_setclock (&attr, CLOCK_MONOTONIC);

这可能会导致 pthread_cond_init 返回 EINVAL

如果您可以重新编译您的glib,您可以取消定义HAVE_PTHREAD_CONDATTR_SETCLOCK

否则我会尽可能更新 glibc

关于c++ - 从静态构造函数代码调用时 pthread 库失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30491839/

相关文章:

c++ - 使用互斥锁同步 2 个进程

c++ - 数组和指针作为参数和返回值

c - 为什么 printf 函数不打印我希望它打印的列表的值?

c - glibc 的 atomic_forced_read 函数的目的是什么?

使用 malloc 或堆栈的 C sprintf 函数

检查程序参数是否等于单个字符

c++ - boost geometry + WGS84,有经纬度,但不是高度?

c++ - 如何使用 C++ 将函数声明为全局函数?

c++ - png block 的 CRC32 计算与真实 block 不匹配

gcc - glibc-2.15 无法删除 `/var/db/Makefile'