2011-08-21 4 views
2

내 GUI에서 주 창에 목록 저장소 트리 뷰가 있습니다. 사용자가 행을 두 번 클릭하면 대화 상자가 나타납니다. 문제는 대화 상자에 채워지는 데이터가 처리하는 데 시간이 걸리기 때문에 대화 상자 계산을 수행하기 위해 스레드를 늘려주는 것입니다. (사용자 더블 클릭 행이, 대화 상자가 로딩 메시지와 함께 즉시 팝업과 결국 채워지면, 즉 스레드를 반환 할 때)GTK의 스레드와 교착 상태 문제

In main: 
....... 
g_signal_connect (G_OBJECT (m_treeview), "row_activated", G_CALLBACK (m_row_activated), 
        (gpointer) main_window); 
....... 

In m_row_activated: 
......... 
// combo_box and dialog are GtkWidget* global variables 
create_dialog(dialog, combo_box); // function creates the combobox 
set_combo_box_with_loading_message; 
gtk_widget_show_all (dialog); 
thread m_thread (bind (&do_dialog_calculations, data1, data2, combobox)); 
......... 

In do_dialog_calculations: 
......... 
// do_calculations takes about 15 seconds to complete 
do_calculations(MyData data1, MyData data2, combobox); 
gdk_threads_enter(); 
gtk_combo_box_append_text(...); 
gdk_threads_leave() 

모든 것이 잘 작동하지만 내 문제는 사용자가 대화 상자를 닫을 때 do_dialog_calculations의 do_calculations가 완료되기 전에. 대화 상자가 파괴되면 내 combobox가 파괴되고 gtk_combo_box_append_text에 대한 호출이 실패합니다.

In do_dialog_calculations: 
......... 
do_calculations(MyData data1, MyData data2, combobox); 
gdk_threads_enter(); 
if (GTK_IS_COMBO_BOX (combobox)) 
    gtk_combo_box_append_text(...); 
gdk_threads_leave() 

을하지만이 GTK_IS_COMBO_BOX에 대한 호출에서 교착 상태가 발생합니다

나는 그것을 업데이트하기 전에 콤보 상자를 테스트하기 위해 노력했다. GTK_IS_COMBO_BOX가 아마도 gdk_threads_enter()를 호출하는 beause라고 생각합니다. 또한 NULL에 대한 테스트를 시도했습니다.

if (combobox == NULL) 

그러나 작동하지 않는 것 같습니다. 이 문제를 해결하는 방법에 대한 제안?

업데이트 : GTK_IS_COMBO_BOX의 교착 상태는 대화 상자가 열리면 (즉, do_calculations()이 완료되기 전에 발생합니다.) 대화 상자가 닫히면 결국 업데이트됩니다. 또한 콤보 박스 검사를 전환하면 전화 gdk_threads_enter()를 쓰기 전에 :.

if (GTK_IS_COMBO_BOX (combobox) 
{ 
    gdk_threads_enter(); 
    gtk_combo_box_append_text(...); 
    gdk_threads_leave(); 
} 

내가 대화 상자를 파괴 할 때이 코드가 실행되기 전에 어떤 교착 상태가 발생하지 그러나, 나는 GTK_IS_COMBO_BOX 검사가 완료되면 사용자가 대화 상자를 닫습니다 드문 가능성을 두려워 해요.

PS - 스레드를 사용하여 대화 상자 계산을 수행합니다. 대화 상자는 모달이 아니므로 대화 상자가 채워지는 동안 사용자가 기본 UI로 다른 작업을 수행 할 수있게하려고합니다.

답변

1
나는 GTK_IS_COMBO_BOX 아마 gdk_threads_enter 호출 beause이 생각()

나는이 경우 생각하지 않습니다. 이 매크로는 일반적으로 매우 간단하며 잠금을 기대하지 않습니다. 사실, gdk_threads_enter에 대한 전체적인 생각은 라이브러리 자체가 이것을 호출해서는 안된다는 것입니다. 다른 스레드에서 실행 중임을 알고있는 코드 만 사용해야합니다.

내 생각은 다음과 같습니다. g_thread_initgdk_threads_init에 전화하는 것을 잊었습니까?

또한 염두에 두어야 할 것은 ... 기본적으로 gdk_threads_enter은 재귀 뮤텍스를 사용하지 않습니다. 어떤 사람들은 재귀 뮤텍스에 종교적인 반대가 있지만, 그것은 gdk_threads_enter 사용을 가질 수있다 :

static GStaticRecMutex my_gdk_lock; 

static void my_gdk_lock_enter() {g_static_rec_mutex_lock(&my_gdk_lock);} 
static void my_gdk_lock_leave() {g_static_rec_mutex_unlock(&my_gdk_lock);} 

// ... 

    g_thread_init(NULL); 

    g_static_rec_mutex_init(&my_gdk_lock); 

    gdk_threads_set_lock_functions(G_CALLBACK(my_gdk_lock_enter), 
            G_CALLBACK(my_gdk_lock_leave)); 

    gdk_threads_init(); 

// ... 

업데이트 : 당신이 대화 상자를 파괴하고 콤보 상자를 채우는 사이의 경쟁 조건을 가지고있는 것처럼 귀하의 코멘트에서 소리가 난다. 한 가지 잠재적 인 해결책은 비동기 작업자가 작업을 수행하는 동안 해제되지 않도록 콤보 상자 (예 : gtk_widget_ref)의 참조 횟수를 늘리는 것입니다. 그런 다음 다른 스레드가 더 이상 포인터를 필요로하지 않을 때 gtk_widget_unref으로 놓습니다.

+0

빠른 답장을 보내 주셔서 감사합니다. gtk_main()을 호출하기 전에 g_thread_init 및 gdk_threads_init를 호출합니다. g_thread_init (NULL); gdk_threads_init(); gtk_init (는 argc, &argv); ....... gdk_threads_enter(); 아마 gtk_main(); gdk_threads_leave();. 내가 GTK_IS_COMBO_BOX 전에 대화 상자가 선택되어 파괴 될 때 는 흥미롭게도, 교착 상태가 발생합니다 예를 들어, 행을 두 번 클릭하면 대화 상자가 팝업되고 (~ 15 초 후) 채워집니다.하지만 행을 두 번 클릭하고 즉시 대화 상자를 파괴하면 GTK_IS_COMBO_BOX 검사에서 멈 춥니 다. – Tim

+0

@Tim - 주석 읽기 다른 문제가있는 것 같아 답변을 업데이트했습니다 – asveikau

+0

모든 도움을 주신 asveikau에게 감사드립니다! – Tim