2

在多线程 C 程序中,我使用了 GLib 的 GList 功能(https://developer.gnome.org/glib/2.35/glib-Doubly-Linked-Lists.html#g-list-append),其中多个线程创建了自己的列表。我观察到不可预知的崩溃,有时在应用程序加载时就发生了。堆栈跟踪显示 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

或这样的消息:

内存错误:[25628]:GSlice:断言失败:sys_page_size == 0 中止(核心转储)

(process:15426): GLib-ERROR (recursed) **: gmem.c:157: failed to allocate 137438953456 >bytes aborting... Aborted (core dumped)

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

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

4

4 回答 4

1

你在使用 GThread 吗?:

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

看看这个页面

于 2013-05-16T06:40:36.657 回答
0

首先,调试符号可能会有所帮助。如何获取它们的详细描述在 gnome live上进行了描述,具体取决于您使用的发行版。

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

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

一旦你完成了它(使用调试符号并使用 valgrind 运行),你应该对正在发生的事情和错误可能在哪里有更好的了解。请注意,它不会得到所有错误,但它会帮助解决最常见的情况。

于 2013-05-18T19:07:59.060 回答
0

参考此页面中的文档:

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

于 2018-07-06T18:27:49.950 回答
-1

与大多数其他简单的 GLib 数据结构一样,GList 不是线程安全的。但是,由于您没有同时从多个线程修改同一个列表,因此这应该没有问题。我认为实际上导致您的段错误的是对 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;
}

(我没有测试这个)

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

于 2013-05-18T18:40:08.470 回答