按GTK按钮停止CPU密集型操作

时间:2012-07-13 16:24:24

标签: c gtk glib

我正在扩展一个GTK应用程序,该应用程序执行一组占用高CPU负载的操作。我希望通过单击GUI中的按钮来包含停止此操作的可能性。 问题是,正如预期的那样,来自按钮的信号实际上是在操作完成后触发的。

目前,代码有点像这样:

[...]
// code snippet to show the dialog and to enable user interactions with the buttons on the lower side of the window
while(TRUE) {
    gint run = gtk_dialog_run (window_main);
    if (run == GTK_RESPONSE_APPLY) {
        gboolean success = start_long_operation();
    }
    else if (run == GTK_RESPONSE_HELP) {
        open_about();
    }
    else if (run == GTK_RESPONSE_CANCEL) {
        stop_long_operation();
    }
    else {
        gtk_widget_destroy (window_main);
        return;
    }
}

我已经声明了一个全局变量busy_state,它由long操作的函数检查:如果它是TRUE,那么内部循环就会继续循环。否则,循环退出,函数返回结果。

stop_long_operation()只是将此全局变量设置为FALSE。

如前所述,我不能按“停止”按钮并“发送”GTK_RESPONSE_CANCEL直到操作完成,因为它会阻止整个窗口。

我已尝试在while (g_main_context_iteration(NULL, FALSE))函数中使用stop_long_operation()技巧,如gtk的文档中所述,但没有结果。

我真的需要设置多线程功能吗?我可以避免这个吗? 谢谢你的帮助。

2 个答案:

答案 0 :(得分:2)

如果您可以将长时间操作分解为多个较小的任务,则可以避免使用线程。最简单的方法是创建一个您将传递给g_idle_add(或g_idle_add_full)的回调。每次回调运行时,它都会执行少量工作,然后返回TRUE。任务完成后,返回FALSE并且不再运行回调。如果要中断任务,只需将g_idle_add返回的值传递给g_source_remove即可删除回调。

如果你无法分解操作,那么线程几乎是你唯一的选择。 g_thread_new是执行此操作的低级方法,但使用GThreadPool通常更容易。更高级的选项是使用g_simple_async_result_run_in_thread

答案 1 :(得分:1)

如果你不想使用线程,这是另一种选择(虽然你应该使用线程,这是非常不安全的):

使用流程。流程要简单得多,可以让您获得更大的灵活性。这是你需要做的:

  • 创建另一种C / C ++ /任何您希望执行该任务的程序的语言
  • 使用spawn()popen()
  • 生成它
  • (可选)使用命令行或IPC
  • 传递参​​数
  • 按下该按钮时,使用UNIX上的kill()调用或Win32终止函数来终止该进程。您可以在UNIX上使用SIGTERM并注册处理程序,以便可以进行受控关闭。