2

我有一个程序(延时制作器),它有两个更新wx.StaticBitmap. 当两个线程访问wx.StaticBitmap它时,它会因错误而崩溃

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

我尝试用谷歌搜索答案,并尝试自己解决,但我仍然无法弄清楚。

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

#!/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查看我的答案解决了它。

4

2 回答 2

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

在主线程中。

于 2011-10-18T04:07:59.983 回答
0

我解决了它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()
于 2011-11-07T00:10:58.830 回答