You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Gtk线程阻塞函数执行问题:指纹验证函数延迟执行排查

问题描述

我用Python编写了一段代码,尝试同时启动Gtk窗口和指纹验证线程,但fp.run_verification函数必须等Gtk窗口关闭后才会执行。相关代码如下:

主程序代码

import threading
from fpysensor import fp
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class MainWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title="Hello, World!")
        self.set_border_width(10)
        
        label = Gtk.Label()
        label.set_label("Hello, World!")
        self.add(label)

def run():
    win = MainWindow()
    win.connect("destroy", Gtk.main_quit)
    win.show_all()
    Gtk.main()

threading.Thread(target=run).start()
threading.Thread(target=fp.run_verification, args=("127.0.0.1", 5000)).start()

while True:
    pass

fp模块代码

from fpysensor import __fingerprint
from ctypes import c_char_p

def run_enrollment(ip_addr: str, port: int): 
    """
    Run the fingerprint enrollment process
    """

    __ip_cp = c_char_p(ip_addr.encode('utf-8'))
    __fingerprint.py_run_enrollment(__ip_cp, port)
def run_verification(ip_addr: str, port: int):
    """
    Run verification against the fingerprints stored
    """
    __ip_cp = c_char_p(ip_addr.encode('utf-8'))
    __fingerprint.py_run_verification(__ip_cp, port)

共享库加载代码

__fingerprint = ctypes.CDLL(f"{__wd}/lib.so")

我通过fp模块调用lib.so共享库,想确认:是Gtk阻塞了所有线程,还是我的C库存在问题?


问题原因及解决办法
  1. 核心问题:主线程的死循环
    代码末尾的while True: pass会让主线程持续占用CPU,结合CPython的GIL(全局解释器锁)机制,这个死循环会一直持有GIL,导致其他子线程无法获得执行权限——包括指纹验证线程。只有当Gtk窗口关闭、Gtk.main()退出后,主线程的死循环才会让GIL调度出现变化,但这并非正确的执行逻辑。

  2. Gtk的线程规范
    Gtk并非线程安全,所有UI相关操作必须在主线程执行。你当前把Gtk窗口放到子线程运行的做法不符合规范,后续可能引发未知问题。正确的模式是将Gtk事件循环放在主线程,把指纹验证这类耗时操作放到子线程。

  3. 修复后的代码示例
    移除主线程的死循环,将Gtk逻辑移回主线程:

    import threading
    from fpysensor import fp
    import gi
    gi.require_version('Gtk', '3.0')
    from gi.repository import Gtk
    
    class MainWindow(Gtk.Window):
        def __init__(self):
            Gtk.Window.__init__(self, title="Hello, World!")
            self.set_border_width(10)
            
            label = Gtk.Label()
            label.set_label("Hello, World!")
            self.add(label)
    
    # 指纹验证放在子线程运行,设置daemon=True让线程随主线程退出
    threading.Thread(target=fp.run_verification, args=("127.0.0.1", 5000), daemon=True).start()
    
    # Gtk事件循环在主线程执行
    win = MainWindow()
    win.connect("destroy", Gtk.main_quit)
    win.show_all()
    Gtk.main()
    
  4. C库排查方向
    如果按上述修改后问题仍存在,再排查C库:检查lib.so中的py_run_verification函数是否存在阻塞逻辑,或者是否在内部未正确释放GIL。但从当前代码看,主线程的死循环是最直接的诱因。

内容的提问来源于stack exchange,提问作者Parker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 14:03:25