python 线程崩溃

发布于 2024-12-10 14:14:57 字数 2574 浏览 0 评论 0原文

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

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

我尝试了Google 搜索寻找答案,我尝试自己解决它,但我仍然无法弄清楚。

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

#!/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 解决了它,请参阅我的答案。

I have a program (time lapse maker) which has two threads that updates a wx.StaticBitmap. When the two threads access the wx.StaticBitmap it crashes with the error

python: xcb_io.c:221: poll_for_event: Assertion `(((long)
(event_sequence) - (long) (dpy->request)) <= 0)' failed.

I tried a Google search for the answer and I tried to solve it myself but I still can't figure it out.

Simple piece of code that reproduces this error (this is not the actual program):

#!/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()

I solved it with wx.PostEvent See my answer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

暮光沉寂 2024-12-17 14:14:57

避免崩溃和各种异常行为的最简单方法是确保只有主线程处理 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

在主线程中。

The easiest way to avoid crashes and anomalous behavior of all sorts is to ensure that only the main thread handles the GUI. You could try to do it by finding and locking critical code blocks, but in my opinion that's a losing game. Much easier to synchronize the processing thread(s) with the main thread using events:

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>

in the processing thread, and

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

in the main thread.

凝望流年 2024-12-17 14:14:57

我用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()

I solved it with 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()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文