Tairan Liu
Tairan Liu

Reputation: 37

python multiprocessing child process trigger parent event or method

I am using multiprocessing to create a child process, then the child process will do some time consuming long time work which may never end.

What I want to do is when the child process finishes one step, it will trigger an event of the parent process or just call some functions.

Here is part of my script:

class WorkerProcess(multiprocessing.Process):
    def __init__(self, port, addresslist, result_queue):
        multiprocessing.Process.__init__(self)
        self.exit = multiprocessing.Event()
        self.serialPort = port
        self.addressList = addresslist
        self.sch = SerialCommunication(self.serialPort, self.addressList)
        self.result_queue = result_queue

    def run(self):
        while not self.exit.is_set():
            self.sch.RegularLoadInfo()
            self.result_queue.put(self.sch.rawData)
            # here trigger event or method in parent process, or let the queue put trigger it

    def shutdown(self):
        try:
            self.sch.stopSerial()
        except Exception:
            print(Exception)
        self.exit.set()

class DataExchange(object):
    def __init__(self):
        self._serialOn = False
        self.workerSerial = None

    def get_serialOn(self):
        return self._serialOn

    def set_serialOn(self, value):
        self._serialOn = value
        if self.serialOn == True:
            result = multiprocessing.Queue()
            self.workerSerial = WorkerProcess(self.serialPort, self.addressList, result)
            self.workerSerial.daemon = True
            self.workerSerial.start()

        elif self.serialOn == False:
            self.workerSerial.shutdown()

    serialOn = property(get_serialOn, set_serialOn)

    def OnUpdate(self, event):
        # triggered by child process
        # do something
        pass

Thanks in advance.

Upvotes: 0

Views: 3936

Answers (1)

hansaplast
hansaplast

Reputation: 11573

You cannot call a method in another process directly, but you have two possibilities:

a) parent waits until child sends

You'll need to set up a queue to communicate from the child to the parent (or a pipe if you need to communicate both ways) and then make the parent block (run get()) until the child sends data (runs put()).

Since you already have set up a queue result in your code you either want to take this or hand in another queue to the __init__ constructor of WorkerProcess.

In the parent process do something like this:

        result = multiprocessing.Queue()
        self.workerSerial = WorkerProcess(self.serialPort, self.addressList, result)
        self.workerSerial.daemon = True
        self.workerSerial.start()
        while True:
            event = result.get()
            if event is None:
                break
            if event == 'update':
                self.OnUpdate()
        self.workerSerial.terminate()

You'll need to define how the child communicates that he sent the last element (aka the "sentinel"), I chose None in the example code above.

Once the parent gets the sentinel, it runs terminate() on the child to end it.

b) parent polls for changes

If the parent needs to do stuff alongside waiting for the result, you'll need to periodically check if there's stuff in your queue:

# do stuff in parent
if not result.empty():
    event = result.get()
    # process event as above and terminate if `None`

Upvotes: 2

Related Questions