PyGTK: gobject.idle_add() и timeout_add() с потоками

Есть ли какая-либо однозначная документация, указывающая, нужны ли блокировки (любого рода) или нет для idle_add() / timeout_add() и / или фактических обратных вызовов, установленных ими?

def work(*args):
  # (1) gtk.gdk.threads_enter() #needed?
  self.ui.change_some_label()
  # (2) gtk.gdk.threads_leave() #?

# (3) gtk.gdk.threads_enter()   #?
gobject.idle_add (work)
# (4) gtk.gdk.threads_leave()   #?

def main():
  gtk.gdk.threads_init()
  #...

Нужны ли 1+2 и / или 3+4? Для каких версий pygtk это применимо? Я нацеливаюсь отдельно на 2.12 (на встроенной платформе) и 2.24 (на рабочем столе). Темы из-за gstreamer.

Для базовых функций C g_idle_add(), g_timeout_add() я нашел обсуждение gtk-app-devel, в котором говорится

Если вы вызвали gdk_threads_init, то обработчики простоя и тайм-аута будут работать без блокировки потока gdk, и вам придется самостоятельно добавлять вызовы gdk_threads_enter/ оставлять, если вы работаете с графическим интерфейсом.

... хотя это с 2004 года. Мне на удивление трудно найти четкую, конкретную документацию для GTK+-2 или для PyGTK.

Многие ответы на SO поддерживают планирование GUI через idle_add, без блокировок / критических секций (например, GUI не обновляется из другого потока при использовании PyGtk)

1 ответ

Решение

Призвание g_idle_add() а также g_timeout_add() не требует блокировки: они являются поточно-ориентированными операциями и гарантируют, что обратный вызов будет вызван в GMainContext это в настоящее время вращается основной цикл.

документация, которую вы связали, говорит, что обратному вызову нужно будет получить мастер-блокировку GDK; обратный вызов вызывается GLib, но блокировка обеспечивается GDK, поэтому вам необходимо получить его явно, чтобы избежать прерывания потоков во время передачи обратного вызова.

по этой причине C API обеспечивает gdk_threads_add_idle() а также gdk_threads_add_timeout() функции (и их полные () варианты), которые гарантируют вызов вашего обратного вызова с удерживаемой блокировкой GDK. PyGTK не переносит эти функции, потому что он также должен был бы удерживать блокировку интерпретатора Python; это означает, что вам нужно будет не забыть позвонить gdk_threads_enter()/gdk_threads_leave() себя в обратном вызове.

Другие вопросы по тегам