GTK中Python的线程在PyGObject反射中有变化吗?

27 投票
1 回答
4318 浏览
提问于 2025-04-16 22:53

我正在把一个程序从PyGTK转换到PyGObject introspection,第一次遇到线程方面的问题。我的程序有一个需要花费一些时间才能完成的过程,所以我会弹出一个对话框,里面有一个进度条,并且我使用一个线程来处理这个过程并更新进度条。在PyGTK中这一切都运行得很好,但转换到PyGObject后,我遇到了各种线程问题:程序卡住了,而且卡在不同的地方等等。所以我觉得可能有什么地方变了,但我搞不清楚是什么。

这里有一个简单的PyGTK进度条示例:http://aruiz.typepad.com/siliconisland/2006/04/threads_on_pygt.html。在那个页面上,代码是可以正常工作的。我把它转换成了PyGObject introspection,结果遇到了和我程序一样的问题:程序卡住了,进度条没有正确更新等等。

import threading
import random, time
from gi.repository import Gtk, Gdk
#Initializing the gtk's thread engine
Gdk.threads_init()


class FractionSetter(threading.Thread):
    """This class sets the fraction of the progressbar"""

    #Thread event, stops the thread if it is set.
    stopthread = threading.Event()

    def run(self):
        """Run method, this is the code that runs while thread is alive."""

        #Importing the progressbar widget from the global scope
        global progressbar 

        #While the stopthread event isn't setted, the thread keeps going on
        while not self.stopthread.isSet() :
            # Acquiring the gtk global mutex
            Gdk.threads_enter()
            #Setting a random value for the fraction
            progressbar.set_fraction(random.random())
            # Releasing the gtk global mutex
            Gdk.threads_leave()

            #Delaying 100ms until the next iteration
            time.sleep(0.1)

    def stop(self):
        """Stop method, sets the event to terminate the thread's main loop"""
        self.stopthread.set()

def main_quit(obj):
    """main_quit function, it stops the thread and the gtk's main loop"""
    #Importing the fs object from the global scope
    global fs
    #Stopping the thread and the gtk's main loop
    fs.stop()
    Gtk.main_quit()

#Gui bootstrap: window and progressbar
window = Gtk.Window()
progressbar = Gtk.ProgressBar()
window.add(progressbar)
window.show_all()
#Connecting the 'destroy' event to the main_quit function
window.connect('destroy', main_quit)

#Creating and starting the thread
fs = FractionSetter()
fs.start()

Gtk.main()

在Gdk的线程功能文档中,强调在运行gdk_threads_init()之前,必须先运行g_thread_init(NULL)。但是要运行这个,你需要链接一些额外的库。如果我尝试通过introspection导入GLib,然后运行GLib.thread_init(),我会得到以下错误:

>>> from gi.repository import GLib
>>> GLib.thread_init(None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/site-packages/gi/types.py", line 44, in function
    return info.invoke(*args)
glib.GError: Could not locate g_thread_init: `g_thread_init': /usr/lib/libglib-2.0.so.0: undefined symbol: g_thread_init

我猜这是因为没有链接额外的线程库。如果这就是我线程问题的原因,那我该如何像那些库已经链接一样使用GLib呢?

1 个回答

27

我自己解决了这个问题,方法是查看了一些用Python写的Gnome程序(这次是Gnome数独,实际上它帮了我几次)。

关键是你需要在代码开始的时候调用 GObject.threads_init(),而不是像C语言文档里说的那样调用 GLib.thread_init()

撰写回答