Python -Thread -Crash
-
22-10-2019 - |
Frage
Ich habe ein Programm (Zeitrafferhersteller) mit zwei Threads, die a aktualisiert werden wx.StaticBitmap
. Wenn die beiden Threads auf die zugreifen wx.StaticBitmap
Es stürzt mit dem Fehler ab
Python: xcb_io.c: 221: poll_for_event: asssertion `(((lang) (Event_sequence) - (lang) (dpy-> request) <= 0) 'fehlgeschlagen.
Ich habe es ausprobiert Google-Suche Für die Antwort und ich habe versucht, es selbst zu lösen, aber ich kann es immer noch nicht herausfinden.
Einfacher Code, der diesen Fehler reproduziert (Dies ist nicht das eigentliche Programm):
#!/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()
Ich habe es mit gelöst wx.PostEvent
Siehe meine Antwort.
Lösung 2
Ich habe es mit gelöst 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()
Andere Tipps
Der einfachste Weg, um Abstürze und anomales Verhalten aller Art zu vermeiden, besteht darin, sicherzustellen, dass nur der Hauptfaden die GUI behandelt. Sie könnten versuchen, es zu tun, indem Sie kritische Codeblöcke finden und sperren, aber meiner Meinung nach ist das ein verlorenes Spiel. Viel einfacher, den Verarbeitungs -Thread (n) mit dem Haupt -Thread mit Ereignissen zu synchronisieren:
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>
im Verarbeitungs -Thread und
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
im Hauptfaden.