LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 2955|回复: 1

GTK+的线程简介

[复制链接]
发表于 2008-12-22 10:09:07 | 显示全部楼层 |阅读模式
一般的GTK+程序都只有一个线程,就算有timer out还有idle也都是在main loop里面是同步执行的。
在执行widget的时候,对图形界面的画图操作,有两种形式,一种是阻塞的,比如gdk_draw_something或者cairo_draw_something。另外一种是非阻塞的,比如gtk_widget_queue_draw,gdk_window_invalidate_rect,这些非阻塞的操作会把expose事件放入事件队列,等到main loop空闲的时候再去真正的重画。如果在此后CPU一直忙的话,那么界面是不能得到刷新的。所以如果要做的更实时的话,应该采用的是阻塞的操作。但因为widget都是双缓冲的,所以即使用阻塞式的方法绘图的话,离屏的表面跟在屏的表面的交换还是要在loop idle的时候才会进行。也就是说GTK+的框架决定了,它的刷图不可能做到实时。所以一定要达到实时绘图的话,大家还是考虑OpenGL和OpenInventor吧。
GTK+的库里面,glib是线程安全的,gdk,gtk,pango,cairo这些库函数都是非线程安全的,所以在多线程的环境下,调用这些函数之前都是需要上锁的,为了达到支持多线程的目的,GTK+特地提供了一个全局的锁,可以使用gdk_threads_enter和gdk_threads_leave进行加锁和解锁。
如果在main loop的外面,开头调用了g_thread_init和gdk_threads_enter,结尾调用了gdk_threads_leave,那么这个loop里面的每个关于绘图的操作都是能自动加锁保护的,例外的是timeout还有idle回调,这些回调如果有绘图操作的话,那么是需要程序员手动加锁保护的。
所以如果有新的线程加入的话,它在对界面更新之前,应该加锁保护,完成之后,立刻释放锁。新线程创建的timeout和idle回调也应该加锁保护,因为这些回调是在main loop的线程里被调用的。
对win32的开发来讲,是有其特殊性的,很多情况下加锁和解锁不是必须的。有些gtk的函数在多线程环境下调用会产生死锁,如gtk_widget_show。这些东西还是要摸索,没有现成的文档可循。比如说main loop之外的线程在对toplevel的window的layout改变进行操作的时候,将会产生死锁。这类问题的解决方案是把那些引起死锁的操作放置到idle或者timeout的回调里去执行
 楼主| 发表于 2009-5-21 09:07:44 | 显示全部楼层
上文有点不妥的地方是在对GTK+的实时刷图的地方,经过自己的实践还是能证明,在win32的运行环境下,有一大帮子函数还是具有实时绘图功能的,其中包括所有的cairo一族的绘图函数,包括对widget的model数据的更改也是能立刻体现在界面上的。至于其中的原理,我现在的推测是最终的windows gdiplus的线程是有守护功能的,它会在接到请求之后,将离屏表面blit到在屏表面上去。但这些线程却是在进程里动态生存的。不知道windows os采用了什么机制,可以动态的给进程增加和销毁线程,却不损失性能。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表