Существует несколько проблем, препятствующих правильному запуску вашего кода.
Прежде всего, вам не позвоните в gobject.threads_init()
(после import gobject
) в начале вашей программы. Этот вызов заставляет PyGTK освобождать GIL при входе в основной цикл. Неспособность вызвать это сделает потоки бесполезными. (В последнем PyGObject с Python 3, это no longer necessary.)
Вторая проблема, и это одна тривиальна, является то, что вы неправильно строит один-элементный кортеж для использования в качестве args
аргумента threading.Thread
конструктора - это должен быть args=(maxSec,)
, а не args=(maxSec)
.
После этих двух изменений ваша программа отображает ожидаемый результат.
Наконец, as andlabs points out и documentation confirms, не разрешено вызывать код GTK из любого потока, кроме потока, который запускает основной цикл. Вместо вызова функций GTK рабочие потоки могут использовать gobject.idle_add
для планирования кода, который будет выполняться в потоке графического интерфейса. (Если поток GUI простаивает, как и должно быть, это произойдет быстро). Другими словами, вы должны заменить gtk.main_quit()
на gobject.idle_add(gtk.main_quit)
. Если функция или принимает аргументы, вместо этого используйте gobject.idle_add(lambda: gtk_call_here(...)
. Хотя совершенно правильно создавать несколько рабочих потоков в программе GTK, они должны избегать прямых вызовов в GTK.
Кроме того, согласно документации, поток, который запускает основной цикл, должен быть тем же самым потоком, который инициализирует GTK. Таким образом, правильная программа не должна import gtk
(которая инициализирует ее) перед запуском потока графического интерфейса. Вот версия вашего кода, которая реализует это:
import threading
# Event marking the GUI thread as having imported GTK. GTK must not
# be imported before this event's flag is set.
gui_ready = threading.Event()
def run_gui_thread():
import gobject
gobject.threads_init()
import gtk
gui_ready.set()
gtk.main()
gui_thread = threading.Thread(target=run_gui_thread)
gui_thread.start()
# wait for the GUI thread to initialize GTK
gui_ready.wait()
# it is now safe to import GTK-related stuff
import gobject, gtk
def countdown(maxSec):
while maxSec > 0:
print maxSec
maxSec -= 1
gobject.idle_add(gtk.main_quit)
worker = threading.Thread(target=countdown, args=(5,))
print 'starting work...'
worker.start()
# When both the worker and gui_thread finish, the main thread
# will exit as well.
Нет, вы не можете запустить 'gtk.main()' в другом потоке из вашего другого кода GTK +. Вам нужно будет запустить другой материал в отдельном потоке. Вы также не можете запустить 'gtk.main_quit()' в отдельном потоке; вам нужно будет использовать 'glib.idle_add()' для очереди на функцию, которая будет запускаться в потоке GTK +. Сожалею. – andlabs
Если вам нужен только таймер, вы также можете использовать 'glib.timeout_add()'. – elya5