gpt4 book ai didi

c++ - GTK中线程的死锁问题

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:34:31 25 4
gpt4 key购买 nike

在我的 GUI 中,我的主窗口中有一个列表存储 TreeView 。当用户双击一行时,会弹出一个对话框。问题是我在对话框中填充的数据需要一段时间来处理,所以我所做的是启动一个线程(使用增强线程)来进行对话框计算。

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 之前关闭对话框时完成。如果对话框被销毁,我在其中的组合框将被销毁并且我对 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()。我也试过测试 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 执行其他操作。

最佳答案

I think this is beause GTK_IS_COMBO_BOX probably calls gdk_threads_enter()

我不这么认为。这些宏通常非常简单,我不希望它获取锁。事实上,据我所知,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),这样当您的异步 worker 正在做某事时它就不会被释放。然后在其他线程不再需要指针时使用 gtk_widget_unref 释放它。

关于c++ - GTK中线程的死锁问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7140336/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com