Question

I am trying to set a class variable of a Process class from outside, to indicate that the while loop inside the process should finish.

However, although the variable appears to get set just fine, the old value is retrieved from run(self). I have tried using threading.Thread where this works. However, the problem with Thread is that it doesn't always start when start() is called. Sometimes it waits for the scp process to be finished, which kills the point of using a Thread for this scenario.

from multiprocessing import Process
        class LogParserThread(Process):
            def __init__(self):
                super(LogParserThread, self).__init__()
                self.scp_done = False
                self.flights_to_add = ()

            def stop(self):
                self.scp_done = True
                print 'Stopping: ' + str(self.scp_done)


            def run(self):
                file_list = ()
                while self.scp_done is False or len(file_list) > 0:
                    print 'Status ' + str(self.scp_done) + ' ' + str(len(file_list))
                    if (len(file_list) > 1):
                        print ' Case 1 '
                        f = file_list[0]
                        os.system('rm -rf ' + f + '*')
                    if (len(file_list) is 1 and self.scp_done is True):
                        print ' Case 2 '
                        f = file_list[0]
                        os.system('rm -rf ' + f + '*')
                    update file_list

        files_to_copy = "file1 file2 file3"
        parser_thread = LogParserThread()
        parser_thread.start()
        print 'BEFORE COPY ' + str(parser_thread.scp_done)
        os.system('scp -C remote:' + files_to_copy + ' ' + '/destination/')
        print 'AFTER COPY ' + str(parser_thread.scp_done)
        parser_thread.stop()
        print 'AFTER STOP ' + str(parser_thread.scp_done)
        parser_thread.join()
        print 'AFTER JOIN ' + str(parser_thread.scp_done)

These are the prints from a test run:

BEFORE COPY: False
AFTER COPY False
Stopping: True
AFTER STOP True
Status False 1
Status False 1
Status False 1
Status False 1
Status False 1
Status False 1
Was it helpful?

Solution

On Unix, subprocesses are spawned using os.fork. The fork copies globals (or uses copy-on-write) so each process (the parent and the child) have their own copy of the globals. On Windows, a second Python process is spawned and the calling module is imported. In either case (on Unix or Windows) when the parent modifies a global variable, the child's global variable of the same name does not change. Thus calling parser_thread.stop() in the main process does not affect the value of self.scp_done in the subprocess.

multiprocessing does provide certain objects which can facilitate sharing state between processes, such as mp.Value. For a simple boolean value, you could also use an mp.Event:

import multiprocessing as mp
import time

class LogParserProcess(mp.Process):
    def __init__(self):
        super(LogParserProcess, self).__init__()
        self.done = mp.Event()
        self.flights_to_add = ()

    def stop(self):
        self.done.set()
        print 'Stopping: ' + str(self.done.is_set())

    def run(self):
        file_list = ()
        while not self.done.is_set() or len(file_list) > 0:
            print 'Status ' + str(self.done.is_set()) + ' ' + str(len(file_list))

files_to_copy = "file1 file2 file3"
proc = LogParserProcess()
proc.start()
print 'BEFORE COPY ' + str(proc.done.is_set())
time.sleep(1)
print 'AFTER COPY ' + str(proc.done.is_set())
proc.stop()
print 'AFTER STOP ' + str(proc.done.is_set())
proc.join()
print 'AFTER JOIN ' + str(proc.done.is_set())

prints

BEFORE COPY False
Status False 0
...
Status False 0
AFTER COPY False
Status False 0
Status False 0
Status False 0
Stopping: True
AFTER STOP True
AFTER JOIN True
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top