GTK中线程的死锁问题
deadlock problem with threads in GTK
在我的GUI中,我在主窗口中有一个列表存储树视图。当用户双击一行时,会弹出一个对话框。问题是,我在对话框中填充的数据需要一段时间来处理,所以我所做的是启动一个线程(使用boost线程)来进行对话框的计算。
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_computation完成之前关闭对话框。如果对话框被销毁,则其中的组合框将被销毁,并且我对gtk_combo_box_append_text的调用将设置fault。
我尝试在更新组合框之前测试它:
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()。我也试过测试NULL
if (combobox == NULL)
但这似乎也不起作用。对于如何解决这个问题有什么建议吗?
UPDATE: GTK_IS_COMBO_BOX的死锁只有在对话框打开后立即关闭时才会发生(即在do_calculation()完成之前)。如果我让对话框静止不动,它最终会更新。此外,如果我在写入前切换组合框复选框调用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,而对话框填充。
我想这是因为GTK_IS_COMBO_BOX可能调用了gdk_threads_enter()
我认为情况并非如此。这些宏通常非常简单,我不希望它带锁。事实上,据我所知,gdk_threads_enter
的整个思想是库本身不应该调用它,只有知道它在另一个线程中运行的代码才应该调用它。
我的想法是:你忘记给g_thread_init
和gdk_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();
// ...
Update:从你的评论中,听起来你在破坏对话框和填充组合框之间有一个竞争条件。一个潜在的解决方案是增加组合框的引用计数(即gtk_widget_ref
),以便在异步工作程序执行某些操作时不会释放它。然后,当其他线程不再需要该指针时,使用gtk_widget_unref
释放该指针。
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 如何在没有死锁和/或争用的情况下正确使用 std::mutex C++?
- 用C++中的std::condition_variable将线程置于死锁中会有风险吗
- 使用 std::async 时死锁,将来作为成员
- 如何调试读写器锁的死锁?
- 为什么在Visual Studio 2013上的std::this_thread::sleep_for上死锁
- localtime() 函数正在调用 ___lll_lock_wait_private(),这会使线程陷入死锁
- 如何重现 Boost 进程文档提示的死锁?
- 多线程Windows GUI应用程序中的死锁
- 为什么printf会导致与future.get的死锁,而cout则不会?
- C++中具有阻塞队列和障碍的死锁
- 死锁使用 std::mutex 来保护多个线程中的 cout
- 避免并发等待对象中的死锁
- 在VC++中从DLLMAIN内部调用D3D的CREATEDEVICE时,它会创建一个死锁(loaderlock?)。有没有办法克服这个问题?最终目标内
- 当用2个螺纹锁定时,将recursive_mutex死锁
- 解决死锁问题,在主线程中等待多个工作线程完成 (C++11)
- 如何理解C++并发操作中同类实例导致死锁的问题
- 通过套接字发送的图像流-服务器死锁问题
- MPI_Sendrecv_replace() 死锁问题
- GTK中线程的死锁问题