【问题标题】:wxPython GUI crashing due to uncaught exception 'NSRangeException'wxPython GUI 由于未捕获的异常“NSRangeException”而崩溃
【发布时间】:2017-10-21 16:04:49
【问题描述】:

我读过 pub/sub 机制是一种线程安全的方式,可以从线程到 GUI (https://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/) 进行通信

下面的程序,已经从一个较大的一个减少到问题的本质,通过pub/sub机制从线程到GUI的wx.TextCtrl区域进行多次写入后崩溃。为了试验几种写入速率,可以在time.sleep(x) 语句中进行更改。无论x 是什么,它都会崩溃(我自己测试了从 0.1 到 100 秒),这与线程写入 GUI 的频率无关。

基本上,GUI 创建文本控件并订阅发布/订阅机制。线程定期写入发布者。它工作正常,直到异常崩溃:

2017-10-21 13:50:26.221 Python[20665:d07] An uncaught exception was raised
2017-10-21 13:50:26.222 Python[20665:d07] NSMutableRLEArray insertObject:range:: Out of bounds
2017-10-21 13:50:26.222 Python[20665:d07] ([…])
2017-10-21 13:50:26.223 Python[20665:d07] *** Terminating app due to uncaught exception 'NSRangeException', reason: 'NSMutableRLEArray 
insertObject:range:: Out of bounds'
*** First throw call stack:
([…]
)
libc++abi.dylib: terminating with uncaught exception of type NSException

“越界”可能与我无法通过 Python 代码访问的索引有关……我无法更进一步。有人可以帮忙吗?

使用Python 2.7.12 | wxPython 3.0.2.0
运行Mac OS X 10.9.5 |在平台上x86_64

代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

__version__ = '04'

import sys
import threading
import time
import platform

try:
    import wx
except ImportError:
    raise ImportError ("The wxPython module is required to run this program")

try:
    from pubsub import pub
except ImportError:
    from wx.lib.pubsub import pub


class CrashFrame(wx.Frame):
    def __init__(self,parent,id,title):
        wx.Frame.__init__(self,parent,id,title)

        self.hor_sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.textlogger = wx.TextCtrl(self, size=(520,110), style=wx.TE_MULTILINE | wx.VSCROLL, value="" )
        self.hor_sizer.Add(self.textlogger)
        self.SetSizerAndFit(self.hor_sizer)
        self.Show(True)

        self.crashthread = SocketClientThread()

        self.run()

    def run(self):
        self.logthistext('Using Python {} | wxPython {}'.format(sys.version.split()[0], wx.VERSION_STRING))
        self.logthistext('Is thread running ? - %s' % self.crashthread.isAlive())

        # Create a listener in the GUI form
        pub.subscribe(self.logthistext, 'fromSocketListener')

    def logthistext(self, msg):
        self.textlogger.AppendText('{}\n'.format(msg)) # a good way to write on the text area


class SocketClientThread(threading.Thread):
    def __init__(self):
        super(SocketClientThread, self).__init__()
        self.alive = threading.Event()
        self.alive.set()
        self.start() # thread will start at creation of the class instance

    def run(self):
        while self.alive.isSet():
            data = 'A bunch of bytes'
            pub.sendMessage('fromSocketListener', msg=data)
            time.sleep(10) # or 0.1 or 100, whatever, it crashes
            continue



if __name__ == '__main__':
    app = wx.App()
    frame = CrashFrame(None,-1,'Crash Program - v{}'.format(__version__))
    app.MainLoop()

【问题讨论】:

    标签: thread-safety wxpython


    【解决方案1】:

    wxPython 的线程安全方法

    wx.PostEvent
    wx.CallAfter
    wx.CallLater

    def run(self):
        x=0
        while self.alive.isSet():
            data = 'A bunch of bytes-'+str(x)
            wx.CallAfter(pub.sendMessage,'fromSocketListener', msg=data)
            time.sleep(0.2) # or 0.1 or 100, whatever, it crashes
            x +=1
    

    【讨论】:

    • 谢谢罗尔夫。它工作正常。伟大的 !我的理解是发布/订阅机制本身不是线程安全的。 CallAfter 或 CallLater 是实际的线程安全平均值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多