gtk idle_add не работает? - PullRequest
       7

gtk idle_add не работает?

4 голосов
/ 27 августа 2010

У меня есть приложение с двумя потоками: GUI и некоторая фоновая работа.Я пытаюсь отправить запросы в основной поток для обновления GUI (переместить индикатор выполнения), но это не похоже на работу.Я свел это к действительно минимальному примеру:

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()

Это, я думал, должно напечатать что-то со стандартной ошибкой из основного потока / потока GUI, но ничего не происходит.И он также не завершается, поэтому gtk.main_quit не вызывается.

Кроме того, добавление вывода в stderr ведет себя странно.Если я изменю функцию потока на:

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

, я вижу 1, иногда 2 строки на выходе.Это похоже на какое-то состояние гонки, когда основной поток входит в gtk.main, но я не знаю, почему это так.

Ответы [ 3 ]

5 голосов
/ 27 августа 2010

Вам необходимо инициировать поддержку потоков в glib перед использованием glib в многопоточной среде.Просто позвоните:

glib.threads_init()

Перед вызовом функций glib.

3 голосов
/ 27 августа 2010

Почему бы не использовать glib.timeout_add_seconds(1, idle) и вернуть False из idle() вместо того, чтобы запускать поток и затем спать 1 секунду?Запуск функции ожидания из другого потока довольно избыточен, поскольку функции ожидания уже выполняются в другом потоке.

РЕДАКТИРОВАТЬ:

"Запуск функции ожидания из другого потокаизбыточный ", я имел в виду, что вам не нужно запускать функцию ожидания, чтобы связываться с графическим интерфейсом и обновлять индикатор выполнения.Это миф, что вы не можете связываться с GUI в других потоках.

Позвольте мне повторить здесь то, что необходимо для выполнения вызовов GTK из других потоков:

  1. Call glib.threads_init() или gobject.threads_init(), в зависимости от того, что у вас есть, как описано в ответе Ванзы.
  2. Позвоните gtk.gdk.threads_init().Я почти уверен, что вы правы в своем ответе, это нужно назвать только до gtk.main().Документы C предлагают вызывать его до gtk_init(), но он вызывается во время импорта в PyGTK, если я не ошибаюсь.
  3. Заключите в скобки ваш звонок на gtk.main() между gtk.gdk.threads_enter() и gtk.gdk.threads_leave().
  4. Заключает в скобки любые вызовы функций GTK из:

    • потоков, отличных от основного потока
    • бездействующих функций
    • таймаутов
    • в основном любой обратный вызов, кроме обработчиков сигналов

    между gtk.gdk.threads_enter() и gtk.gdk.threads_leave().

Обратите внимание, что вместо того, чтобы окружать ваши вызовы enter /leave пар, вы также можете использовать with gtk.gdk.lock: и выполнять свои звонки в этом with -блоке.

Вот некоторые ресурсы, которые также объясняют этот вопрос:

0 голосов
/ 27 августа 2010

Следующее заставляет меня работать выше:

Вызов gtk.gdk.threads_init(), прежде чем делать что-либо еще: перед запуском потоков, перед вводом gtk.main().Я думаю, что на самом деле это нужно вызвать только перед вводом gtk.main(), но достаточно просто вызвать его, пока все однопоточно и просто.пример), вызов gtk.gdk.threads_enter() перед GTK (легко сделать только в верхней части функции) и вызов gtk.gdk.threads_leave(), до конца функции.

gtk.gdk.threads_init() кажетсятакже сказать PyGTK не держать GIL, когда он засыпает - я думаю, что я пропустил некоторые выходные данные из aux.поток в примере только потому, что спящий основной поток (спящий в gtk.main()) все еще удерживал GIL.gtk.gdk.threads_init(), насколько я могу судить, прививает хороший модж в PyGTK и GTK +.По этой причине gtk.gdk.threads_init() необходим, даже если вы запускаете поток, который не касается GTK +, ничего не делает с glib, gobject и т. Д., Просто выполняет базовые вычисления.

...