在另一个线程中运行函数而不是gui

时间:2010-06-08 09:31:08

标签: c multithreading gtk

我有简单的C / gtk +应用程序。我在这个应用程序中有功能,它在gtkimageview小部件中加载图像:

gboolean 
main_win_open( MainWin* mw, const char* file_path)
{
  ...       
  //loading and displaing image in gtkimageview
  ...
}

加载图像是可行的,但我需要在另一个线程中运行此函数,然后是主gui表单;

我有功能:

void*
argument_thread(void *args)
{
  Data *data = (Data*)args;
  gdk_threads_enter();
  main_win_open (data->win,data->argv);
  gdk_threads_leave();
}

数据main_win_open函数参数的结构:

typedef struct _Data
{
  MainWin *win;
  char* argv;
} Data;

然后在main函数中创建线程并运行它:

int main(int argc, char** argv)
{
    GError*   err;
    GThread*  thread;   
    Data data;
    MainWin *win;

    // init thread support
    if(!g_thread_supported())
        g_thread_init(NULL);
        gdk_threads_init();

    // init GTK+
    gtk_init (&argc, &argv);

    win = (MainWin*)main_win_new();
    gtk_widget_show(GTK_WIDGET(win));

    data.win = win;
    data.argv = argv[1];

    if (argc == 2)
    {
       thread = g_thread_create((GThreadFunc)argument_thread,&data,FALSE, &err);
    }

    gdk_threads_enter();
    gtk_main();
    gdk_threads_leave();
}

但是当我尝试从命令行运行app并尝试加载大尺寸图像时,gui正在阻止。

怎么了?

谢谢。

3 个答案:

答案 0 :(得分:2)

如果您在之前调用gdk_threads_enter(),则开始加载图像,那么在加载图像时GUI将被冻结且无响应。基本上,您可以在一个单独的线程中首先加载图像然后创建GUI。您可能想要的是在加载图像的耗时任务之后调用gdk_threads_enter(),并在快速更新GUI时声明GDK锁定。

需要锁定GDK,因为GTK +不是线程安全的。然而,X11(可能还有mac)实现是threadaware,这意味着任何线程都可以使用任何API(但当然一次只能使用一个)。

另一方面,Windows API不能以这种方式从任何线程使用,因此也不是Windows版本的GTK +。如果不了解有关Windows API的详细信息,最好只从一个线程调用GTK +。这并不意味着线程应用程序是不可能的。您仍然可以在另一个线程中加载图像,然后使用例如gtk_idle_add()在主线程中进行GUI更新。

答案 1 :(得分:1)

重新发布此处的代码http://pastebin.com/BkLJ7UkR

我认为你不能在主线程中做那种东西......(当然,从文件读取,但不是GdkPixbuf的东西)

你应该做的是将main_win_open分成两个部分,一个是文件读取,一个是将数据推入pixbuf加载器,然后通过g_idle_add()调用第二个函数(这是线程安全的,它' ll将回调添加到mainloop)

如果你想这样做,我建议一次性将整个图像加载到内存中然后通过g_idle_add传递

然而,我强烈怀疑这些东西是否需要...你加载的图像有多大,它花费了很多时间加载它? (基本上我认为你做错了就是在非常不需要线程时使用线程)

答案 2 :(得分:0)

来自gdk_threads_enter()的文档:

  

“这个宏标志着一个开头   关键部分,其中GDK和GTK +   可以安全地调用函数   没有引起竞争条件。的只有   一次一个线程可以是这样的   批评部分。“

如果我没有弄错,这就是您的应用仍然阻止的原因。对于GThread'ed应用程序,对gdk_threads_enter / _leave的调用是不必要的,因此请尝试删除它们。