python线程崩溃

时间:2011-10-18 00:36:30

标签: python multithreading exception assertion wxwidgets

我有一个程序(时间流逝制造商),它有两个更新wx.StaticBitmap的线程。 当两个线程访问wx.StaticBitmap 时,它会因错误而崩溃

  

python:xcb_io.c:221:poll_for_event:断言`(((长)   (event_sequence) - (长)(dpy->请求))< = 0)'失败。

我尝试了一个Google search的答案,我试图自己解决,但我仍然无法理解。

重现此错误的简单代码 (这不是实际程序)

#!/usr/bin/env python

import wx
import time,os.path,glob,threading

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):

        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.bitmap_1 = wx.StaticBitmap(self, -1, wx.NullBitmap)

        self.__set_properties()
        self.__do_layout()

        wx.CallAfter(self._img)
    def __set_properties(self):

        self.SetTitle("frame_1")


    def __do_layout(self):

        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_1.Add(self.bitmap_1, 0, 0, 0)
        self.SetSizer(sizer_1)
        sizer_1.Fit(self)
        self.Layout()



    def _img(self):
             Thread1= threading.Thread(target=self._img1)
             Thread1.start()
             Thread2 = threading.Thread(target=self._img2)
             Thread2.start()

    def _img1(self):
            frames = glob.glob("/path/to/pngs/*.png")
        frames.sort()
        for i in range(len(frames)):
            if os.path.isfile(frames[i]) and i%2 == 0:
                print frames[i]
                wx.Yield()
                ##time.sleep(0.5)
                wx.CallAfter(self.bitmap_1.SetBitmap,wx.Bitmap(frames[i], wx.BITMAP_TYPE_ANY))
                wx.CallAfter(self.Update)
    def _img2(self):
            frames = glob.glob("/path/to/pngs/*.png")
        frames.sort()
        for i in range(len(frames)):
            if os.path.isfile(frames[i]) and i%2 == 1:
                print frames[i]
                wx.Yield()
                ##time.sleep(0.5)
                wx.CallAfter(self.bitmap_1.SetBitmap,wx.Bitmap(frames[i], wx.BITMAP_TYPE_ANY))
                wx.CallAfter(self.Update)

if __name__ == "__main__":
    app = wx.PySimpleApp(0)
    wx.InitAllImageHandlers()
    frame_1 = MyFrame(None, -1, "")
    app.SetTopWindow(frame_1)
    frame_1.Show()
    app.MainLoop()

我用wx.PostEvent解决了这个问题。请参阅我的回答。

2 个答案:

答案 0 :(得分:4)

避免所有类型的崩溃和异常行为的最简单方法是确保只有主线程处理GUI。您可以尝试通过查找和锁定关键代码块来实现,但在我看来,这是一场失败的游戏。使用事件更容易使处理线程与主线程同步:

while run:
    self.timer_evt.wait()        # wait for main thread to unblock me
    self.timer_evt.clear()
    <process stuff, put results in queue or shared variables>

在处理线程中,

def tick(self):
    if run:
        <update GUI from queued data or shared variables>
        self.timer_evt.set()            # unblock processing thread
        self.root.after(ms, self.tick)  # reschedule the GUI update

在主线程中。

答案 1 :(得分:1)

我用wx.PostEvent解决了它:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# generated by wxGlade 0.6.3 on Mon Oct 17 19:59:55 2011

import wx
import time,os.path,glob,threading
# begin wxGlade: extracode
# end wxGlade


ID_START = wx.NewId()
ID_STOP = wx.NewId()

# Define notification event for thread completion
EVT_RESULT_ID = wx.NewId()

def EVT_RESULT(win, func):
    """Define Result Event."""
    win.Connect(-1, -1, EVT_RESULT_ID, func)

class ResultEvent(wx.PyEvent):
    """Simple event to carry arbitrary result data."""
    def __init__(self, data):
        """Init Result Event."""
        wx.PyEvent.__init__(self)
        self.SetEventType(EVT_RESULT_ID)
        self.data = data
class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MyFrame.__init__
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.bitmap_1 = wx.StaticBitmap(self, -1, wx.NullBitmap)
        self.__set_properties()
        self.__do_layout()
        # end wxGlade
    self.frames = ""
    EVT_RESULT(self,self.OnResult)
        wx.CallAfter(self._img)
    def __set_properties(self):
        # begin wxGlade: MyFrame.__set_properties
        self.SetTitle("frame_1")
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: MyFrame.__do_layout
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_1.Add(self.bitmap_1, 0, 0, 0)
        self.SetSizer(sizer_1)
        sizer_1.Fit(self)
        self.Layout()
        # end wxGlade
    def OnResult(self, event):
        """Show Result status."""
        if event.data is None:
            pass
        else:
        self.bitmap_1.SetBitmap(wx.Bitmap(event.data, wx.BITMAP_TYPE_ANY))
# end of class MyFrame
    def _img(self):
             Thread1= threading.Thread(target=self._img1)
             Thread1.start()
             Thread2 = threading.Thread(target=self._img2)
             Thread2.start()

    def _img1(self):
            frames = glob.glob("/home/mitch/Pictures/*.png")
        frames.sort()

        for i in range(len(frames)):
            if os.path.isfile(frames[i]) and i%2 == 0:
                print frames[i]
                ##wx.Yield()
                ##time.sleep(0.5)
                wx.PostEvent(self, ResultEvent(frames[i]))

    def _img2(self):
            frames = glob.glob("/home/mitch/Pictures/*.png")
        frames.sort()

        for i in range(len(frames)):
            if os.path.isfile(frames[i]) and i%2 == 1:
                print frames[i]
                ##wx.Yield()
                ##time.sleep(0.5)
                wx.PostEvent(self, ResultEvent(frames[i]))

if __name__ == "__main__":
    app = wx.PySimpleApp(0)
    wx.InitAllImageHandlers()
    frame_1 = MyFrame(None, -1, "")
    app.SetTopWindow(frame_1)
    frame_1.Show()
    app.MainLoop()