[wxWidgets] Multithreaded Logging, aber nur 1 Thread darf auf GUI zugreifen



  • Hiho!
    Ich hab folgendes Problem: In meinem Programm arbeiten mehrere Threads parallel. All diese Threads erzeugen Log-Messages, welche ich in der GUI ausgeben moechte, und zwar in der Statusbar meines Haupt-Frames.
    Das Problem dabei: es darf ja immer nur ein Thread auf die GUI-Elemente zugreifen/sie veraendern, naemlich derjenige, der die GUI erzeugt hat (In der Tat stuerzt das Programm unter Linux auch prompt bei der ersten Log-Ausgabe deswegen ab, unter Windows rennts trotzdem).

    Deshalb die Frage: wie setz ich sowas am besten um?

    EDIT: Mein erster Gedanke war sowas in der Art von "der Logger schreibt die Logs nur in einen Buffer, und der GUI-Thread schreibts dann raus", aber da ich die wx-Mainloop ja nicht beeinflussen kann, kann ich dem GUI-Thread ja nicht sagen "hey, schau mal nach obs neue Log-Messages gibt die du rausschreiben sollst". Was anderes faellt mir grad nicht ein. 😕


  • Mod

    Du musst einen eigenen Event schreiben, der dann vom Thread an die GUI geschickt wird.
    Einfach mal im Forum suchen, in meinem 2. wxWidgets Artikel steht auch was zu eigenen Events.



  • Hmm... bist du sicher dass das auch funktioniert? Momentan ist das so implementiert (Python):

    myEVT_CALLBACK = wx.NewEventType()
    EVT_CALLBACK = wx.PyEventBinder(myEVT_CALLBACK, 1)
    
    class CallbackEvent(wx.PyCommandEvent):
    	def __init__(self, evtType, id):
    		wx.PyCommandEvent.__init__(self, evtType, id)
    
    class ThreadsafeCallback:
    	""" Derive from this class if you want threadsafe callbacks. """
    
    	def __init__(self, id = None):
    		if not id:
    			id = wx.NewId()
    		self._id = id		
    		wx.GetApp().Bind(EVT_CALLBACK, self.__callback_impl)
    
    	def _trigger(self):
    		""" Triggers the callback. """
    
    		print "trigger thread:", threading.currentThread().getName()
    		evt = CallbackEvent(myEVT_CALLBACK, self._id)
    		wx.GetApp().ProcessEvent(evt)
    
    	def __callback_impl(self, evt):
    		""" Just a wrapper so callback() doesn't receive an evt-object """
    
    		print "callback thread:", threading.currentThread().getName()
    		try:
    			self.callback()
    		except:
    			pass
    
    	def callback(self):
    		pass
    

    Wenn ich das Programm dann laufen lass, gibt das dann sowas aus:

    gui thread:  MainThread
    callback thread: Thread-1
    trigger thread: Thread-1
    

    (Die "gui thread" Ausgabe wird durch einen Buttondruck ausgegeben). Der Callback wird also im selben Thread ausgefuehrt wie die Funktion, welche die Nachricht generiert hat. Die eigentliche GUI laeuft in einem anderen Thread. 😕 Was mach ich falsch?



  • Hmm... Problem geloest! 🙂 Wenn ich den neuen Event mittels AddPendingEvent (statt mit ProcessEvent) hinzufuege, wird der callback im GUI-Thread ausgefuehrt 🙂


Anmelden zum Antworten