简体   繁体   中英

Multiprocessing: Parent/Child w/ GUI (tkinter)

I am creating a parent program with UI that spawns multiple subprograms, also with GUI. All child processes need to talk to a parent (trying PIPE atm). Parent uses a QUEUE to terminate all processes.

EDIT: The programs run on Raspberry Pi 4 w/ Raspbian OS and python 3.7.3.

Main program: bridge.py

import tkinter as tk
from time import sleep
import multiprocessing as mp
import os
import sys

import simple

class Main_Comm():
    def __init__(self):
        self.kill_queue = mp.Queue()
        self.p_conn, self.ch_conn = mp.Pipe()
        print("MAIN: PIPE: child: {}".format(self.ch_conn))
        self.proc = mp.Process(target=simple.my_dev, \
                    args=(self.kill_queue, self.ch_conn, ))
        self.proc.start()

    def Stop_Devices(self):
        #self.kill_queue.put(True)
        self.proc.join()
        print("Wait for processes to finish ...")
        sleep(2)
        print("Device OFF!")

    def Info(self):
        print("Info: QUEUE {}, PIPE {}".format(self.kill_queue, self.ch_conn))

class MainApp_bridge(tk.Tk):
    def __init__(self, master=None, title="Default"):
        #super().__init__()
        tk.Tk.__init__(self)
        self.title(title)
        self.btn = tk.Button(self, text="QUIT", command=self.on_quit)
        self.btn.pack(padx=20, pady=20)

        self.communicator = Main_Comm()
        self.communicator.Info()

        self.mainloop()

    def on_quit(self):
        print("Sending termination message via QUEUE ...")
        self.communicator.Stop_Devices()
        sleep(1)
        print("Shutting down main tread, HAL ...")
        sleep(1)
        self.destroy()

def main():
    root_bridge = MainApp_bridge(title="BRIDGE")

if __name__ == "__main__":
    main()

# EOF

and one child (simple.py)

import tkinter as tk
import os
import random
from time import sleep
import sys

class MainApp_simple(tk.Tk):
    def __init__(self, parent=None, title="Device",
            FLAG=False, kq=None, chc=None):
        #super().__init__()
        tk.Tk.__init__(self)
        self.title(title)
        self.b_QUIT = tk.Button(self, text="QUIT", command=self.on_quit)
        self.b_QUIT.pack(side="top", padx=30, pady=30)
        self.window=self
        self.kq = kq
        self.chc = chc
        self.comm_agent = communicator( self.window, self.kq, self.chc )
        self.mainloop()

    def on_quit(self):
        print("CHILD: Quitting ...")
        self.destroy()

class Dev_comm():
    def __init__(self, win, kq, chc):
        self.kq = kq
        self.chc = chc
        self.win = win
        self.mypid = os.getpid()
        print("CHILD: PID is {} and PIPE is {}".format(self.mypid, chc))

def my_dev( kill_queue, child_comm ):
    root_simple = MainApp_simple(
            parent=None,
            title="CHILD", 
            FLAG=False, 
            kq=kill_queue, 
            chc=child_comm
            )

# EOF sim.py

Each programs work fine on their own. If I take out GUI from the bridge, it works. All together, however, I get this:

CHILD: MainApp - pre __init__ .... flushing
MAIN: PIPE: child: <multiprocessing.connection.Connection object at 0xb5989750>
Info: QUEUE <multiprocessing.queues.Queue object at 0xb5dc39d0>, PIPE <multiprocessing.connection.Connection object at 0xb5989750>
CHILD: Entered my_dev function ... flushing ...
XIO:  fatal IO error 25 (Inappropriate ioctl for device) on X server ":0.0"
      after 47 requests (47 known processed) with 2 events remaining.
X Error of failed request:  BadIDChoice (invalid resource ID chosen for this connection)
  Major opcode of failed request:  45 (X_OpenFont)
  Resource id in failed request:  0x2c00004
  Serial number of failed request:  114
  Current serial number in output stream:  120

I just cannot figure it out, Btw; flushing did not provide any new information. the error message begins with XIO...

First I thought it was related to polling the pipes and queues interfering with mainloop()... but apparently not.

Help is greatly appreciated.

Cheers, Radek

EDIT: I thought that perhaps there is some interference between two tk.Tk calls, but I can run multiple child processes with GUI as long as the parent runs in the terminal. Even pipes and queue worked... it's the parent GUI...

Jason Harper actually provided a solution: SPAWN instead of FORK.

The start up seems a bit slower, but everything runs as expected. Even polling the queue and pipes between process works fairly well.

Thank you. Radek

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM