Create windows in multiprocessing process

I'm writing an application using wxPython, that's supposed to start
new processes which should be able to create their own wxPython
windows. I'm using multiprocessing to start the processes, but my
application crashes when the new processes try to create new wxPython
windows.

When the processes are started from outside the wx app mainloop it
works as expected, but when the process is started within the
mainloop, the program crashes with the error messages:
python: Fatal IO error 0 (Success) on X server :0.0.
python: Fatal IO error 0 (Success) on X server :0.0.
python: ../../src/xcb_io.c:221: poll_for_event: Assertion `(((long)
(event_sequence) - (long) (dpy->request)) <= 0)' failed.
python: ../../src/xcb_io.c:221: poll_for_event: Assertion `(((long)
(event_sequence) - (long) (dpy->request)) <= 0)' failed.

Has anybody an idea how to solve this problem?

Here's a small script demonstrating what I'd like to do:

import wx
import multiprocessing
from wx.lib.mixins.inspection import InspectionMixin

## The pSysmon main application.
class MyApp(wx.App, InspectionMixin):
    ''' The wx application class.
    '''
    ## The constructor

···

#
    def __init__(self, redirect=False, filename=None,
                 useBestVisual=False, clearSigInt=True):
        wx.App.__init__(self, redirect, filename, useBestVisual,
                        clearSigInt)

    def onInit(self):
        self.Init() # The widget inspection tool can be called
using CTRL+ALT+i
        return True

class Test(wx.Frame):

    def __init__(self, parent=None, id=wx.ID_ANY, title="Hallo",
size=(1000,600)):
        wx.Frame.__init__(self, parent=parent, id=id, title=title,
pos=wx.DefaultPosition, style=wx.DEFAULT_FRAME_STYLE)
        self.SetMinSize(size)

def startWxProcess():
    app = MyApp()
    dlg = Test()
    dlg.Show()
    p = multiprocessing.Process(target=startChildWxProcess)
    p.start()
    app.MainLoop()

def startChildWxProcess():
    app = MyApp()
    dlg = Test()
    dlg.Show()
    app.MainLoop()

if __name__ == '__main__':
    # Start the first process.
    p = multiprocessing.Process(target=startWxProcess)
    p.start()

    # Start the second process.
    p1 = multiprocessing.Process(target=startWxProcess)
    p1.start()

Don't try to use wx or any UI objects from the child processes. When using the multiprocessing module all the children share state with the parent process, similarly to how multiple threads would, and you can not share a single wx across processes for similar reasons why it won't work with multiple threads.

It may work okay if wx is not imported and no wx.App objects created in the parent process until after the children are spawned. Then if the children import and use wx it should be totally separate instances of wx with no shared state. But personally I'm still not sure I'd trust it. I'd rather organize things with a single UI process and multiple worker processes that communicate results back to the UI as needed.

···

On 3/23/12 1:32 PM, scientificSteve wrote:

I'm writing an application using wxPython, that's supposed to start
new processes which should be able to create their own wxPython
windows. I'm using multiprocessing to start the processes, but my
application crashes when the new processes try to create new wxPython
windows.

When the processes are started from outside the wx app mainloop it
works as expected, but when the process is started within the
mainloop, the program crashes with the error messages:
python: Fatal IO error 0 (Success) on X server :0.0.
python: ../../src/xcb_io.c:221: poll_for_event: Assertion `(((long)
(event_sequence) - (long) (dpy->request))<= 0)' failed.
python: ../../src/xcb_io.c:221: poll_for_event: Assertion `(((long)
(event_sequence) - (long) (dpy->request))<= 0)' failed.

Has anybody an idea how to solve this problem?

--
Robin Dunn
Software Craftsman

This didn't crash on my single core:

import multiprocessing

import wx

class MultiCoreApp(object):

    def __init__(self):

        #import wx

        class MyFrame(wx.Frame):
            def __init__(self, parent, title):
                wx.Frame.__init__(self, parent=parent, title=title)

                panel = wx.Panel(self)
                self.tc = wx.TextCtrl(panel, style=wx.TE_MULTILINE)

                tc_sizer = wx.BoxSizer(wx.VERTICAL)
                tc_sizer.Add( self.tc, 1, wx.ALL | wx.EXPAND, 0)
                panel.SetSizer(tc_sizer)

                sizer = wx.BoxSizer(wx.VERTICAL)
                sizer.Add(panel, 1, wx.ALL | wx.EXPAND, 0)
                self.SetSizer(sizer)

            def write(self, text=''):
                self.tc.AppendText( text + '\n')

        class MyApp(wx.App):

            def OnInit(self):
                self.frame = None
                return True

            def CreateFrame(self, title):
                #self.frame = wx.Frame(None, title=title)
                self.frame = MyFrame(None, title=title)

                self.frame.Show()
                #print('%r' % wx.GetApp())
                #self.frame
                return self.frame

            def write(self, text=''):
                self.frame.write(text)

        self.gui = MyApp(0)

        wx_id_str = str(id(wx))
        text = 'id(wx): %s' % wx_id_str
        self.gui.CreateFrame(text)
        self.gui.frame.write(text)

        self.gui.frame.write()

        app_id_str = str(id(self.gui))
        text = 'id(guiapp): %s' % app_id_str
        self.gui.frame.write(text)

def startWxProcess():
    app = MultiCoreApp()
    app.gui.MainLoop()

if __name__ == '__main__':
    print('id(wx): %d' % id(wx))
    p0 = multiprocessing.Process(target=startWxProcess)
    p0.start()

    print('id(wx): %d' % id(wx))

    del wx
    import wx

    print('id(wx): %d' % id(wx))

    reload(wx)
    print('id(wx): %d' % id(wx))
    p1 = multiprocessing.Process(target=startWxProcess)
    p1.start()