dan*_*an3 4 gtk user-interface multithreading pygtk thread-safety
是否有任何明确的文档说明 idle_add() / timeout_add() 和/或它们安装的实际回调是否需要(任何类型的)锁?
def work(*args):
# (1) gtk.gdk.threads_enter() #needed?
self.ui.change_some_label()
# (2) gtk.gdk.threads_leave() #?
# (3) gtk.gdk.threads_enter() #?
gobject.idle_add (work)
# (4) gtk.gdk.threads_leave() #?
def main():
gtk.gdk.threads_init()
#...
Run Code Online (Sandbox Code Playgroud)
是否需要 1+2 和/或 3+4?这适用于哪些 pygtk 版本?我分别针对 2.12(在嵌入式平台上)和 2.24(在桌面上)。线程是由于 gstreamer。
对于底层的 C 函数 g_idle_add(), g_timeout_add() 我发现了一个gtk-app-devel 讨论,指出
如果你调用了 gdk_threads_init 那么空闲和超时处理程序将在没有gdk 线程锁的情况下运行,如果你在做 gui 的东西,你必须自己添加 gdk_threads_enter/leave 调用。
...虽然这是从 2004 年开始的。我发现很难为 GTK+-2 或 PyGTK 找到清晰、具体的文档。
SO 上的许多答案都通过 idle_add 支持调度 GUI 工作,没有任何锁/关键部分(例如,使用 PyGtk 时 GUI 不会从另一个线程更新)
调用g_idle_add()并且g_timeout_add()不需要锁定:它们是线程安全的操作,并保证回调将在GMainContext当前旋转的主循环中被调用。
您链接的文档说回调将需要获取 GDK 主锁;回调是由 GLib 调用的,但锁是由 GDK 提供的,因此您需要明确获取它以避免在回调发射期间线程中断。
出于这个原因,C API 提供了gdk_threads_add_idle()和gdk_threads_add_timeout()函数(及其 full() 变体),它们保证在持有 GDK 锁的情况下调用您的回调。PyGTK 不包装这些函数,因为它还需要持有 Python 解释器锁;这意味着您需要记住在回调中调用gdk_threads_enter()/gdk_threads_leave()自己。