gtkidle_add 没有运行?

发布于 2024-09-16 14:35:49 字数 823 浏览 6 评论 0原文

我有一个双线程应用程序: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 的某种竞争条件,但我不知道为什么会这样。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

白云不回头 2024-09-23 14:35:49

在多线程环境中使用 glib 之前,需要初始化 glib 的线程支持。只需调用:

glib.threads_init()

在调用 glib 函数之前。

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.

千笙结 2024-09-23 14:35:49

为什么不使用glib.timeout_add_seconds(1,idle)并从idle()返回False而不是启动一个线程然后休眠1秒?从另一个线程启动空闲函数是相当多余的,因为空闲函数已经在另一个线程中运行。

编辑:

“从另一个线程启动空闲函数是多余的”,我的意思是您不必启动空闲函数来扰乱 GUI 并更新进度条。你不能在其他线程中弄乱 GUI,这是一个神话。

让我在这里重申一下从其他线程进行 GTK 调用所需的内容:

  1. 调用 glib.threads_init()gobject.threads_init(),无论您有什么,如 vanza 中所述回答。
  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() 之间。

。请注意,您还可以使用 with gtk.gdk.lock: 并在该内进行调用-块。

这里有一些资源也解释了这个问题:

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:

撩心不撩汉 2024-09-23 14:35:49

以下内容使上述内容对我有用:

在执行其他操作之前调用 gtk.gdk.threads_init():在启动线程之前、在进入 gtk.main() 之前。我认为实际上,这只需要在进入 gtk.main() 之前调用,但调用它很容易,因为一切都是单线程且简单的。

在空闲回调中(示例中为 idle),在 GTK 内容之前调用 gtk.gdk.threads_enter()(只需在函数顶部即可轻松完成) ),并在函数结束之前调用 gtk.gdk.threads_leave()

gtk.gdk.threads_init() 似乎还告诉 PyGTK 在进入睡眠状态时不要保留 GIL - 我认为我丢失了 aux 的一些输出。示例中的线程只是因为休眠主线程(在 gtk.main() 中休眠)仍然持有 GIL。据我所知,gtk.gdk.threads_init() 为 PyGTK 和 GTK+ 注入了良好的魔力。因此,即使您启动一个不接触 GTK+、不使用 glib、gobject 等执行任何操作、仅进行基本计算的线程,也需要 gtk.gdk.threads_init() 。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文