gpt4 book ai didi

c - GTK3 和多线程,替换已弃用的函数

转载 作者:太空狗 更新时间:2023-10-29 16:59:06 25 4
gpt4 key购买 nike

我想在使用线程的应用程序中替换弃用的函数 gdk_threads_enter()/leave()。现在的应用程序运行完美(虽然我不确定这是否是正确的方法)。

我的主循环,运行 gtk_main 和信号处理程序。当我收到一个开始按钮时,我会启动一个线程,该线程沿着主线程在后台运行。我如何从该线程更新 GUI。我知道根据 GTK3 和 GDK3 的文档,他们说通过使用

来避免它
gdk_threads_add_idle() 

gdk_threads_add_timeout() 

但是,如果我希望仅在单击开始时才完成更新,我该怎么做呢?有没有例子。我不是在问如何使用 gdk_threads_add_idle(),我是在问如何在单击开始后在没有线程的情况下在 main 中运行 worker 函数。

单击按钮 --> “在先前的线程中”启动辅助功能 --> 在 GUI 窗口中更新大量 GUI 元素。

最佳答案

您有 3 种方法可以做到这一点:

  1. make computation in the button callback and use gtk_event_pending()/gtk_main_iteration()

  2. use g_idle_add() or others, and gtk_event_pending()/gtk_main_iteration()

  3. use a thread, eventually a mutex, and g_idle_add() or others. Normally, a mutex isn't needed but it may solve some bugs or Heisenbugs.

第三种 解决方案似乎是最好的,因为使用前两种 方法时,我在计算运行时退出应用程序时遇到了一些问题。该应用程序没有退出,并且正在打印大量“Gtk Critical”警告。 (我在 Windows 和 mingw32 上试过)。


1。按钮回调:

如果你想在主 gtk 循环中运行工作线程,你可以直接在按钮回调中进行计算,更新 GUI 并使用 gtk_event_pending() 处理来自它的事件>gtk_main_iteration(),示例代码如下:

void on_button_clicked(GtkButton * button, gpointer data) {

// do some computation...

// modify the GUI:
gtk_label_set_text(label,"text");

// run the main iteration to update the GUI,
// you need to call these functions even if the GUI wasn't modified,
// in order to get it responsive and treat events from it:
while(gtk_events_pending()) gtk_main_iteration();

// do some other computation...

// huge computation in a loop:
while(1) {
// do some computation...

// update the GUI and treat events from it:
while(gtk_events_pending()) gtk_main_iteration();
}
}

2。 g_idle_add():

您还可以使用g_thread_new()gdk_thread_add_idle()(如果某些不受您控制的库可能会使用gdk_threads_enter()/leave()) 或 g_idle_add()g_main_context_invoke():

gboolean compute_func(gpointer data) {

// do some computation...

// modify the GUI:
gtk_label_set_text(label,"text");
// run the main loop to update the GUI and get it responsive:
while(gtk_events_pending()) gtk_main_iteration();

// do some other computation...

// huge computation in a loop:
while(1) {
// do some computation...

// update GUI and treat events from it:
while(gtk_events_pending()) gtk_main_iteration();
}

return FALSE;
}

void on_button_clicked(GtkButton * button, gpointer data) {

g_idle_add(compute_func,data);
}

3。线程和互斥:

某些情况下,使用线程会使计算速度更快,因此当使用不在主 gtk 循环中的工作线程时,以及在添加到主循环的函数中更新 GUI 时,gdk_threads_add_idle()g_idle_add(),您可能必须使用互斥锁锁定对 GUI 的访问,因为访问 GUI 的函数之间可能存在冲突图形用户界面。在应用程序使用之前,必须使用 g_mutex_init(&mutex_interface); 初始化互斥体。例如:

GMutex mutex_interface;

gboolean update_gui(gpointer data) {
g_mutex_lock(&mutex_interface);
// update the GUI here:
gtk_button_set_label(button,"label");
// And read the GUI also here, before the mutex to be unlocked:
gchar * text = gtk_entry_get_text(GTK_ENTRY(entry));
g_mutex_unlock(&mutex_interface);

return FALSE;
}

gpointer threadcompute(gpointer data) {
int count = 0;

while(count <= 10000) {
printf("\ntest %d",count);
// sometimes update the GUI:
gdk_threads_add_idle(update_gui,data);
// or:
g_idle_add(update_gui,data);

count++;
}

return NULL;
}

void on_button_clicked(GtkButton * button, gpointer data) {

g_thread_new("thread",threadcompute,data);
}

如果您需要更新 GUI 的函数以特定顺序执行,您需要添加两个计数器并为使用 g_idle_add()gdk_threads_add_ilde 调用的每个函数分配一个编号():

GMutex mutex_interface;

typedef struct _data DATA;
struct _data {
gchar label[1000];
GtkWidget * w;
int num;
};


int counter = 0;
int counter2 = 0;

gboolean update_gui(gpointer data) {
DATA * d = (DATA *)data;

debutloop:
g_mutex_lock(&mutex_interface);
if(d->num != counter2) {
g_mutex_unlock(&mutex_interface);
goto debutloop;
}
counter2++;
// update the GUI here:
gtk_button_set_label(GTK_BUTTON(d->w),d->label);
// And read the GUI also here, before the mutex to be unlocked:
gchar * text = gtk_entry_get_text(GTK_ENTRY(entry));
g_mutex_unlock(&mutex_interface);

free(d);

return FALSE;
}

gpointer threadcompute(gpointer data) {
int count = 0;

while(count <= 10000) {
printf("\ntest %d",count);

DATA * d = (DATA*)malloc(sizeof(DATA));
sprintf(d->label,"%d",count);
d->w = (GtkWidget*)data;
d->num = counter;
counter++;
// update the GUI:
g_idle_add(update_gui,d);

count++;
}
return NULL;
}

void on_button_clicked(GtkButton * button, gpointer data) {

g_thread_new("thread",threadcompute,button);
}

我还测试了锁定单个小部件而不是整个 GUI 的情况,它似乎可以工作。

关于c - GTK3 和多线程,替换已弃用的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30607429/

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