我有简单的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正在阻止。
怎么了?
谢谢。
答案 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的调用是不必要的,因此请尝试删除它们。