I have a thread that loops receiving socket data and printing it:
def post(self):
while True:
try:
data = pickle.loads(self.sock.recv(1024))
print data[0] % tuple(data[1])
except (socket.error, EOFError):
break
I then have a GUI that redirects stdout to a textctrl like so:
import wx
import sys
import threading
class Redirect:
def __init__(self, ctrl):
self.out = ctrl
def write(self, string):
wx.CallAfter(self.out.AppendText,string)
class GUI(wx.Frame):
def __init__(self, parent):
self.monitor = wx.TextCtrl(self, wx.ID_ANY, \
style = wx.TE_MULTILINE | wx.TE_READONLY)
redir = Redirect(self.monitor)
sys.stdout = redir
self.sizer = BoxSizer(wx.VERTICAL)
self.sizer.Add(self.monitor, 1, wx.GROW | wx.ALL)
self.SetSizer(self.sizer)
self.Show(True)
if __name__ == "__main__":
app = wx.App(False)
frame = GUI(None)
app.MainLoop()
I've also got a second textctrl that accepts input (left out for simplicity). The issue is that sometimes CallAfter(AppendText,string) is not printing out the entire string. It is very rare, but sometimes the print will just be stopped abruptly in the middle of the string, at which point the next string is printed (and the app continues printing the strings as they're received as if nothing happened).
I've no idea what's causing this behavior, I've tried to induce it by typing into the second textctrl to see if that's causing it, but even if I do nothing, these "partial prints" appear every now and then. What's going on?
This is not a real answer, just a way how to replicate the problem:
import wx
import sys
import threading
def post():
a = 0
for stop in range(100):
a = (a + 1) % 10
data = str(a) * 1000 + " <END>"
print(data)
for i, line in enumerate(frame.monitor.Value.split("\n")[:-1]):
if not line.endswith(" <END>"):
print("Invalid line %d" % (i+1))
class Redirect:
def __init__(self, ctrl):
self.out = ctrl
def write(self, string):
wx.CallAfter(self.out.AppendText, string)
class GUI(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent)
self.monitor = wx.TextCtrl(self, wx.ID_ANY, style = wx.TE_MULTILINE | wx.TE_READONLY)
redir = Redirect(self.monitor)
sys.stdout = redir
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.monitor, 1, wx.GROW | wx.ALL)
self.SetSizer(self.sizer)
self.Show(True)
if __name__ == "__main__":
app = wx.App(False)
frame = GUI(None)
t = threading.Thread(target=post)
t.start()
app.MainLoop()
When ran on my setup, I get (usually, not always):
Invalid line 30
Invalid line 63
I tried playing with delays and mutexes / locks, but it seem that I did not find why this happens yet.