2013-05-16 2 views
2

다중 스레드 C 프로그램에서 GLib (https://developer.gnome.org/glib/2.35/glib-Doubly-Linked-Lists.html#g-list-append)의 GList 기능을 사용하여 여러 스레드가 자체 목록을 작성했습니다. 예기치 않은 충돌이 어플리케이션을로드하자마자 발생했습니다. 이 같은GList (glib-doubly-linked-list) 스레드는 안전합니까?

(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 

또는 메시지 :

MEMORY-ERROR: [25628]: GSlice: assertion failed: sys_page_size == 0 Aborted (core dumped)

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

나는 향한 GList의 도입이 모든 충돌의 원인이 믿을 이유가 스택 추적 glist_ * 기능에 약간의 충돌이 같은 몇 가지 메시지를 보여줍니다. 단일 스레드 프로그램에서는 이러한 문제를 본 적이 없습니다.

GList는 본질적으로 스레드로부터 안전합니까? 그렇지 않다면, 내가 뭘해야합니까?

답변

2

After calling g_thread_init(), GLib is completely thread safe.

는 대부분의 다른 간단한 입심 데이터 구조로, 스레드로부터 안전하지 않습니다, this page

+0

저는 POSIX 스레드 (pthread_create 등)를 사용했습니다. 자식 스레드를 생성하기 전에 부모 스레드에서 인수로 NULL을 g_thread_init() 사용해야합니까? –

+1

아니요, g_thread 계열 함수를 사용해야합니다. 반면에 POSIX 스타일 스레드가 사용되면'G_THREADS_IMPL_POSIX'가 정의됩니다. –

+1

계속 : "GLib은 완전히 스레드 안전합니다 (모든 글로벌 데이터는 자동으로 잠김). 그러나 개별 데이터 구조 인스턴스는 성능상의 이유로 자동으로 잠기지 않습니다. 예를 들어 다중 스레드에서 동일한 GHashTable에 대한 액세스를 조정해야합니다.이 규칙의 두 가지 주목할만한 예외는 스레드가 안전하며 더 이상의 응용 프로그램 수준 잠금이 필요하지 않은 GMainLoop 및 GAsyncQueue입니다 여러 스레드에서 액세스 할 수 있습니다. " 스레드는 * 자신의 목록을 만들었지 만 여러 스레드에서 동시에 액세스합니까? – nemequ

-1

의 GList에 봐? GThread을 사용하고 있습니다. 그러나 여러 스레드에서 동일한 목록을 동시에 수정하지 않으므로이 문제가 발생하지 않아야합니다. g_slice_alloc (g_list_append/prepend 호출의 결과)에 대한 여러 개의 동시 호출이 segfaults를 실제로 일으키는 것은 아닌지 생각합니다. 다른 사람들은 전에 same problem에 부딪 혔던 것 같습니다.

/* 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; 
} 
을 :

나는이 문제를 해결 할 방법은 당신이 (의 예로 들어 뒤로 이어지는 보자), 및 쓰기 사용하고있는 메모리를 할당 각 g_list 하나에 대한 뮤텍스 보호 래퍼 함수를 ​​만드는 것입니다

(나는 이것을 테스트하지 않았다)

모든 래퍼 함수에서 동일한 뮤텍스를 사용해야하므로 한 번에 하나의 스레드 만 슬라이스 함수에 들어간다는 점에 유의하십시오.

+0

g_slice API는 스레드 안전해야합니다 (nemequ 주석을 참조하십시오, IIRC 내부적으로 lock-free입니다) - 충돌이 발생하면 a) glib에 버그가있어 업스트림에보고해야합니다 mulithread 프로그램을 사용하여 널리 퍼져 있음) https://bugzilla.gnome.org/ 또는 b) 프로그램 자체에 버그가 있습니다 -'G_SLICE = always-malloc'과 함께 문제가 발생 했으므로 훨씬 더 _ _ _ _ _ _ _ 가능합니다. 그 뜻이지만 시스템 malloc과 슬라이스 모두에 있습니다. 솔루션에서 - 단일 호출 만 보호하므로 메모리와 추가를 해제하는 작업이 동시에 수행됩니다. –

+0

그래서 슬라이스 API와 malloc에 ​​문제가있을지라도 그것을 보호 할 수는 없습니다. –

+0

> "단일 호출 만 보호하므로 메모리를 확보하고 추가 작업을 동시에 수행 할 수 있습니다."- 이해가 안되지만이를 명확히 할 수 있습니까? – Ancurio

0

먼저 디버깅 기호가 도움이 될 수 있습니다. 그것들을 얻는 방법에 대한 자세한 설명은 on gnome live으로되어 있으며 사용중인 배포판에 따라 다릅니다.

앞에서 설명한 것처럼 g_slice API는 스레드로부터 안전합니다. IIRC는 자물쇠가 없거나 그와 매우 가깝도록 설계되었습니다. GLib 데이터 구조는 일반적으로 멀티 스레드 환경에서 사용하는 것이 안전합니다 (인스턴스가 동시에 여러 스레드에서 액세스되지 않는 한) - 그렇지 않은 경우 upstream으로보고해야하는 버그입니다 (단, GLib는 널리 사용됩니다 멀티 스레드 환경을 포함하여 사용되는 경우 명백한 버그가있을 가능성은 매우 낮습니다).

stacktrace가 주어지면 메모리 손상과 같습니다. 내 생각 엔 당신이 버퍼 오버 플로우/어딘가에 어딘가에 g_slice 내부 메모리를 작성하거나 초기화되지 않은 GList 포인터를 사용하여 '임의의 메모리'에 액세스하는 비슷한 효과를 얻었거나 오버플로가 발생하는 몇 가지 이유로 할당 할 음수 값을 전달하려고합니다. 정수의. G_SLICE=always-mallocValgrind 이하로 실행하는 것이 좋습니다. 너무 느리다면 gcc 4.8 이상의 AddressSanitizer와 clang (다른 버전은 기억이 안납니다)과 같은 다른 메소드가 있습니다. 이러한 버그는 GList와 관련된 코드가 아니지만 미묘한 상호 작용 (다른 주소 레이아웃 등)으로 인해 발생할 수 있습니다.

일단 디버깅 기호를 사용하고 valgrind로 실행했다면 벌어지는 일과 버그의 위치에 대해 훨씬 더 잘 알고 있어야합니다.모든 버그를 얻지는 못하지만 대부분의 일반적인 경우에는 도움이 될 것입니다.

+0

GList와 같은 단순한 데이터 구조는 기본적으로 ** 스레드 안전하지 않습니다 **. 소스 코드를 살펴보면 동시성 보호가 없다는 것을 알 수 있습니다. – Ancurio

+0

@Ancurio : 죄송합니다. Clarified - API가 인스턴스가 아니라는 의미였습니다 (즉, 스레드로부터 안전하지 않은 다중 스레드 환경에서 안전하게 사용할 수 있음). –

관련 문제