【问题标题】:Scanning for thread violations with Tkinter使用 Tkinter 扫描线程违规
【发布时间】:2011-03-03 06:06:38
【问题描述】:

我们即将完成对使用 python2.5 和 Tkinter 构建的应用程序的一次非常大的更新,不幸的是,以下错误已经悄悄出现:

alloc: invalid block: 06807CE7: 1 0 0

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

我们以前见过这种情况,这通常是当非 GUI 线程尝试以任何方式通过 Tkinter 访问 TK(TK 不是线程安全的)时导致的 Tcl Interrupter 错误。在 python 中断器使用我们的代码完成后,应用程序关闭时会弹出错误。这个错误很难重现,我想我必须扫描系统中的所有线程,看看它们是否在不应该访问 TK 时访问。

我正在寻找一个神奇的 python 技巧来帮助解决这个问题。我们使用的所有 Tkinter 小部件首先是子类化的,并从自己的 Widget 基类继承。

考虑到这一点,我正在寻找一种方法,将以下检查添加到小部件子类中每个方法的开头:

import thread
if thread.get_ident() != TKINTER_GUI_THREAD_ID:
    assert 0, "Invalid thread accessing Tkinter!"

想到了装饰器作为部分解决方案。但是,我不想手动为每个方法添加装饰器。有没有办法可以将装饰器添加到从我们的 Widget 基类继承的类的所有方法中?还是有更好的方法来完成这一切?或者有没有人有关于这个错误的更多信息?

enter code here

【问题讨论】:

    标签: python multithreading tkinter


    【解决方案1】:

    我不知道你的方法好不好,因为我不了解 Tkinter。

    但这里有一个如何使用元类装饰所有类方法的示例。

    import functools
    
    # This is the decorator
    def my_decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print 'calling', func.__name__, 'from decorator'
            return func(*args, **kwargs)
    
        return wrapper
    
    # This is the metaclass
    class DecorateMeta(type):
        def __new__(cls, name, bases, attrs):
            for key in attrs:
                # Skip special methods, e.g. __init__
                if not key.startswith('__') and callable(attrs[key]):
                    attrs[key] = my_decorator(attrs[key])
    
            return super(DecorateMeta, cls).__new__(cls, name, bases, attrs)
    
    # This is a sample class that uses the metaclass
    class MyClass(object):
        __metaclass__ = DecorateMeta
    
        def __init__(self):
            print 'in __init__()'
    
        def test(self):
            print 'in test()'
    
    obj = MyClass()
    obj.test()
    

    元类覆盖类的创建。它循环遍历正在创建的类的所有属性,并用my_decorator 装饰所有具有“常规”名称的可调用属性。

    【讨论】:

      【解决方案2】:

      我采用了一种稍微简单的方法。我使用了__getattribute__ 方法。代码如下:

      def __getattribute__(self, name):
      
          import ApplicationInfo
          import thread, traceback
      
          if ApplicationInfo.main_loop_thread_id != thread.get_ident():
              print "Thread GUI violation"
              traceback.print_stack()
      
          return object.__getattribute__(self, name)
      

      果然,我们发现了一个不为人知的地方,我们从 TK 中访问状态,而不是在主 GUI 线程中。

      虽然我必须承认我需要检查我的 python,但是看着你的例子感觉很无聊。

      【讨论】:

        猜你喜欢
        • 2015-04-29
        • 1970-01-01
        • 2019-04-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-08
        • 1970-01-01
        • 2011-01-15
        相关资源
        最近更新 更多