2014-01-16 58 views
1

所以我应该在我的程序开始运行,使其线程安全(或线程感知正如我在一些地方已经阅读):Python的GTK + 3安全线程

from gi.repository import Gtk, Gdk, GLib, GObject 
import threading 

GLib.threads_init()  # ? 
GObject.threads_init() # YES! 
Gdk.threads_init()  # ? 

my_app() 

def my_threaded_func(): 
    Glib.idle_add(lambda: some_gui_action()) 
    Glib.timeout_add(300, lambda: some_gui_action()) 

t = threading.Thread(target=my_thread_func) 
t.daemon = True 
t.start() 

Gtk.main() 

那么,我应该在我的线程吗?某种锁?使用Python的线程库安全吗?还是应该在GLib,GObject或Gdk中使用某些东西?我知道这里有很多问题/答案/例子,但它们都互相矛盾,不适用于Gtk + 3,或者不适用于Python,或者仅仅是不完整,甚至我认为Python GI的官方文档(http://lazka.github.io/pgi-docs/ )甚至没有提到GObject.threads_init()和Gdk.threads_init()的存在。

回答

9

https://wiki.gnome.org/Projects/PyGObject/Threading

..但是,Gdk.threads_init() is deprecated,而且我recommmend到:

  • 不叫在所有
  • 使用GLib.idle_add Gdk.threads_init,Gdk.threads_enter /离开,而不是Gdk.threads_add_idle(或任何其他Gdk.threads_ *功能)
  • 推的东西抚摸GDK/GTK主线程使用GLib.idle/timeout_add

为什么?:

  • 不调用Gdk.threads_init意味着将没有锁,这是确定的,如果你从来没有从另一个线程访问GDK。
  • Gdk.threads_enter不做任何事情,因为没有锁定。
  • 在这种情况下,GLib.idle_add等于Gdk.threads_add_idle

关于其他库:

  • 某些GI模块可以发出在其他线程某些信号/回调(GStreamer中GstPlayBin ::大约到完成信号例如);即使你根本没有在你的代码中使用Python线程。 Gdk/Gtk代码不能直接在它们中调用,如果需要,也可以在那里使用idle_add。
  • GLib/GStreamer的很多部分都是线程安全的,可以从其他线程调用。

TL; DR:只有GObject.threads_init()在线程推所有基于GTK/GDK代码给主线程使用GLib.idle_add

+0

您发布的链接使用'Gdk.threads_init()'。你能链接到提及它已被弃用的来源吗?而且,你能解释为什么'GLib.idle_add()'而不是'Gdk.threads_add_idle()'?谢谢。 – jpcgt

+0

@jpcgt更新.. – lazka

+0

@lazca我的应用程序没有崩溃,因为我实施了你的建议。为此非常感谢。还有两件事,使用'GObject.threads_init()'而不是'GLib.threads_init()'的基本原理是什么?毕竟我们使用'GLib.add_idle()'与主线程同步。我读过一些人说,最好使用并行进程而不是线程。你能评论吗?再次感谢。 – jpcgt

0

这里是一个必须读取的原稿如果有人打算在多线程代码中使用GTK。 https://wiki.gnome.org/Attic/GdkLock

这篇文档确实帮助我理解了如何在单个进程中从C以及从python(通过PyGTK只是为了在python中导入gtk)运行GTK。虽然GDK锁可以通过XInitThreads()在Linux中避免,但它不是Windows的解决方案。像g_idle_add()g_timeout_add()这样的功能是防止GUI粉碎的通用解决方案。然而,gdk_threads_enter()和gdk_thread_leave()还没有完全无用。该文档阐明了如果有人想要从不同线程或自定义事件处理程序或g_idle_add()回调更新GUI,如何安全地使用这些锁。