gtk idle_add not running?

余生颓废 提交于 2019-12-07 11:59:09

问题


I have a two-thread application: GUI, and some background work. I'm trying to send requests to the main thread to do GUI updates (move a progress bar), but it doesn't seem to work. I've boiled it down to a really minimal example:

import pygtk
pygtk.require('2.0')
import glib
import gtk

import threading
import sys
import time

def idle():
    sys.stderr.write('Hello from another world.\n')
    sys.stderr.flush()
    gtk.main_quit()

def another_thread():
    time.sleep(1)
    glib.idle_add(idle)

thread = threading.Thread(target=another_thread)
thread.start()
gtk.main()

This should, I thought, print something to standard error from the main/GUI thread, but nothing happens. And it doesn't quit, either, so gtk.main_quit isn't being called.

Also, adding more output to stderr acts weirdly. If I change the thread's function to:

sys.stderr.write('----\n')
sys.stderr.write('----\n')
sys.stderr.flush()
sys.stderr.write('After.\n')
sys.stderr.flush()

I see 1, sometimes 2 lines out output. It looks like some kind of race condition with the main thread entering gtk.main, but I don't know why this would be.


回答1:


You need to init glib's thread support before using glib in a multi-threaded environment. Just call:

glib.threads_init()

Before calling into glib functions.




回答2:


Why not use glib.timeout_add_seconds(1, idle) and return False from idle() instead of starting a thread and then sleeping 1 second? Starting an idle function from another thread is quite redundant, since idle functions already run in another thread.

EDIT:

By "starting an idle function from another thread is redundant", I meant that you don't have to start an idle function in order to mess with the GUI and update the progress bar. It is a myth that you can't mess with the GUI in other threads.

Let me restate here what is needed to do GTK calls from other threads:

  1. Call glib.threads_init() or gobject.threads_init(), whichever you have, as discussed in vanza's answer.
  2. Call gtk.gdk.threads_init(). I am pretty sure you are right in your answer, this only has to be called before gtk.main(). The C docs suggest calling it before gtk_init(), but that's called at import time in PyGTK if I'm not mistaken.
  3. Bracket your call to gtk.main() between gtk.gdk.threads_enter() and gtk.gdk.threads_leave().
  4. Bracket any calls to GTK functions from:

    • threads other than the main thread
    • idle functions
    • timeouts
    • basically any callback other than signal handlers

    between gtk.gdk.threads_enter() and gtk.gdk.threads_leave().

Note that instead of surrounding your calls with enter/leave pairs, you can also use with gtk.gdk.lock: and do your calls within that with-block.

Here are some resources which also explain the matter:

  • http://www.yolinux.com/TUTORIALS/GDK_Threads.html
  • http://blogs.operationaldynamics.com/andrew/software/gnome-desktop/gtk-thread-awareness.html



回答3:


The following makes the above work for me:

A call to gtk.gdk.threads_init() before doing anything else: before starting threads, before entering gtk.main(). I think in reality, this only needs to be called before entering gtk.main(), but it is easy enough to call it while everything is single threaded and simple.

In the idle callback (idle, in the example), a call to gtk.gdk.threads_enter() before GTK stuff (easy to do just at the top of the function), and a call to gtk.gdk.threads_leave(), before the end of the function.

gtk.gdk.threads_init() seems to also tell PyGTK not hold the GIL when it goes to sleep - I think I was missing some output from the aux. thread in the example just because the sleeping main thread (sleeping in gtk.main()) was still holding the GIL. gtk.gdk.threads_init(), as far as I can tell, instills good mojo into PyGTK and GTK+. Because of this, gtk.gdk.threads_init() is needed even if you launch a thread that doesn't touch GTK+, doesn't do anything with glib, gobject, etc., just does basic computation.



来源:https://stackoverflow.com/questions/3579221/gtk-idle-add-not-running

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!