使用Tkinter扫描线程违规

1 投票
2 回答
984 浏览
提问于 2025-04-16 12:53

我们快要完成一个很大的应用更新,这个应用是用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.

我们以前见过这个错误,通常是因为一个非图形界面的线程试图通过Tkinter访问TK,导致了Tcl解释器错误(因为TK不是线程安全的)。这个错误在应用关闭时出现,发生在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

2 个回答

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来装饰所有可以调用的、名字比较“普通”的属性。

0

我选择了一种稍微简单一点的方法。我使用了 __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中访问状态时,并没有在主界面线程里。

虽然我得承认,我需要再复习一下我的Python,看到你的例子让我感觉像个新手。

撰写回答