accident de fil de python
-
22-10-2019 - |
Question
J'ai un programme (temps maker lapse) qui a deux fils qui met à jour une wx.StaticBitmap
. Lorsque les deux fils d'accéder au wx.StaticBitmap
il se bloque avec l'erreur
python: xcb_io.c: 221: poll_for_event: Assertion `(((long) (Event_sequence) - (long) (demande dpy->)) <. = 0) » a échoué
J'ai essayé Google recherche pour la réponse et j'ai essayé de résoudre moi-même mais je ne peux toujours pas comprendre.
simple morceau de code qui reproduit cette erreur (ce n'est pas le programme réel) :
#!/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()
Je l'ai résolu avec wx.PostEvent
Voir ma réponse.
La solution 2
Je l'ai résolu avec 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()
Autres conseils
La meilleure façon d'éviter les accidents et le comportement anormal de toutes sortes est de faire en sorte que seules les principales poignées de fil de l'interface graphique. Vous pouvez essayer de le faire en trouvant et verrouillage des blocs de code critiques, mais à mon avis, c'est un jeu perdant. Beaucoup plus facile de synchroniser le fil de traitement (s) avec le fil conducteur à l'aide d'événements:
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>
dans la chaîne de traitement, et
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
dans le fil principal.