Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C GList(glib双链表)线程安全吗?_C_Linux_Thread Safety_Glib - Fatal编程技术网

C GList(glib双链表)线程安全吗?

C GList(glib双链表)线程安全吗?,c,linux,thread-safety,glib,C,Linux,Thread Safety,Glib,在一个多线程C程序中,我使用了GLib()的GList功能,其中多个线程创建了自己的列表。我观察到不可预测的崩溃,有时是在应用程序加载之后。堆栈跟踪显示glist_*函数中的一些崩溃消息如下: (gdb) bt #0 0x00007fffeb54a964 in g_slice_alloc () from /lib64/libglib-2.0.so.0 #1 0x00007fffeb52aac6 in g_list_append () from /lib64/libglib-2.0.so.0

在一个多线程C程序中,我使用了GLib()的GList功能,其中多个线程创建了自己的列表。我观察到不可预测的崩溃,有时是在应用程序加载之后。堆栈跟踪显示glist_*函数中的一些崩溃消息如下:

(gdb) bt
#0  0x00007fffeb54a964 in g_slice_alloc () from /lib64/libglib-2.0.so.0
#1  0x00007fffeb52aac6 in g_list_append () from /lib64/libglib-2.0.so.0
或者像这样的信息:

(gdb) bt
#0  0x00007fffeb54a964 in g_slice_alloc () from /lib64/libglib-2.0.so.0
#1  0x00007fffeb52aac6 in g_list_append () from /lib64/libglib-2.0.so.0
内存错误:[25628]:GSlice:断言失败:sys\u page\u size==0 中止(堆芯转储)

(进程:15426):GLib错误(递归)**:gmem.c:157:分配137438953456>字节失败 流产。。。 中止(堆芯转储)

我有理由相信,GList的引入导致了所有这些崩溃。在单线程程序中,我从未见过这些问题


GList本身就是线程安全的吗?如果没有,我需要做什么?

您正在使用GThread吗?:

调用g_thread_init()后,GLib是完全线程安全的


请看一下GList,因为大多数其他简单的GLib数据结构都不是线程安全的。但是,由于您没有同时修改来自多个线程的同一列表,因此这应该不会有问题。我认为导致segfault的实际原因是对g_slice_alloc的多个并发调用(由g_list_append/prepend调用产生)。其他人似乎以前也碰到过这种情况

我解决这个问题的方法是为每个分配您正在使用的内存的g_list创建一个受互斥保护的包装函数(以g_list_append为例),并编写:

/* Init this before starting your threads with g_mutex_new() */
static GMutex *g_list_mutex;

GList *safe_list_append(GList *list, gpointer data)
{
    GList *ret;

    g_mutex_lock(g_list_mutex);
    ret = g_list_append(list, data);
    g_mutex_unlock(g_list_mutex);

    return ret;
}
(我没有测试这个)


请注意,您需要在所有包装函数中使用相同的互斥,因此一次只有一个线程进入slice函数。

首先,调试符号可能会有所帮助。关于如何获取它们的详细描述已被描述,并取决于您使用的发行版

如前所述,g_切片API是线程安全的。IIRC设计为无锁或非常接近锁。如前所述,GLib数据结构通常在多线程环境中使用是安全的(只要实例不是同时从多个线程访问的)-如果不是,则应该报告它是一个bug(但是由于GLib被广泛使用,包括多线程环境,它不太可能有一些明显的bug)

鉴于堆栈跟踪,它看起来像内存损坏。我猜您在某个地方有缓冲区溢出/下溢,并在g_片内部内存上写入,或者您使用未初始化的GList指针,具有访问“随机内存”的类似效果,或者您尝试传递一个负值进行分配,由于某些原因导致整数溢出。我建议在下运行
G_SLICE=always malloc
。如果速度太慢,还有其他方法,比如GCC4.8+中的AddressSanitizer和clang(我不记得是哪个版本)。请注意,这些bug可能不在与GList相关的代码中,而是由微妙的交互(不同的地址布局等)引起的

完成后(使用调试符号并使用valgrind运行),您应该对正在发生的事情以及bug可能在哪里有更好的了解。请注意,它不会得到所有的bug,但会对大多数常见情况有所帮助。

参考以下文档:

GLib的一般策略是,所有函数都是不可见的线程安全的,但数据结构操纵函数除外,其中,如果有两个线程操纵同一数据结构,则它们必须使用锁来同步其操作。
GLib为自己的目的创建工作线程,因此GLib应用程序将始终至少有2个线程。

我没有,我使用了POSIX线程(pthread_create等)。在生成子线程之前,我是否应该从父线程使用带有NULL参数的g_thread_init(),但由于性能原因,单个数据结构实例不会自动锁定。因此,例如,您必须协调多个线程对同一GHashTable的访问。此规则的两个显著例外是GMainLoop和GAsyncQueue,它们是线程安全的,不需要从mu访问进一步的应用程序级锁定你说线程创建了自己的列表,但是它们是从多个线程并发访问的吗?嗨,Nemeq,谢谢你的评论。在我的例子中,线程创建了自己的列表,并且只能从同一个线程访问,不会从多个线程进行并发访问。警告g_thread_init从2.32版开始就被弃用,不应在新编写的代码中使用。此功能不再是必需的。GLib线程系统在程序开始时自动初始化。抱歉,我正在阅读一份旧文档:(g_slice api应该是线程安全的(请参阅Nemeq评论,IIRC它在内部是无锁的)-如果它崩溃,那么a)glib中有缺陷,应该向上游报告(鉴于使用mulithread程序的广泛使用,不太可能)on或b)程序内部存在bug-类似的问题也发生在
G_SLICE=always malloc
上,可能性更大,否则这意味着系统malloc和SLICE中都存在bug。作为您的解决方案-您只保护单个调用,因此释放内存和追加操作将同时进行。因此,即使切片API和malloc中出现问题,它也不会对其进行保护。>“您只保护单个调用,因此释放内存和追加操作将同时进行”-我不理解这一点,你能澄清一下吗?编辑修正了。然而,我关于在错误的地方解决错误问题的观点仍然站得住脚。通常,系统库(GLib就是其中之一)是您最不应该查找bug的地方,因为它们通常都经过很好的测试(都是通过单元测试和