0

I know that processes do not share same context in python. But what about singleton objects? I was able to get the child process share same internal object as parent process, but am unable to understand how. Is there something wrong with the code below?

This could be a follow up to this stackoverflow question.

This is the code I have:

Singleton.py:


import os

class MetaSingleton(type):
     _instances = {}

def __call__(cls, *args, **kwargs):
    if cls not in cls._instances:
        cls._instances[cls] = super(MetaSingleton, cls).__call__(*args, **kwargs)
    return cls._instances[cls]

class Singleton:
   __metaclass__ = MetaSingleton

   def __init__(self):
       self.key="KEY TEST"
       print "inside init"

   def getKey(self):
       return self.key

  def setKey(self,key1):
       self.key = key1

  process_singleton.py:


  import os
  from Singleton import Singleton

  def callChildProc():
       singleton = Singleton()
       print ("singleton key: %s"%singleton.getKey())

  def taskRun():
       singleton = Singleton()
       singleton.setKey("TEST2")
       for i in range(1,10):
           print ("In parent process, singleton key: %s" %singleton.getKey())
        try:
           pid = os.fork()
        except OSError,e:
           print("Could not create a child process: %s"%e)

        if pid == 0:
            print("In the child process that has the PID %d"%(os.getpid()))
           callChildProc()
           exit()

       print("Back to the parent process")

 taskRun()
coder
  • 129
  • 1
  • 1
  • 10
  • Which operating system? On linux like systems, forked child processes have a copy-on-write view of the parent. Anything setup by the parent before the fork is seen by the child. – tdelaney Aug 30 '18 at 16:10
  • Oh, I see. Does that mean, that once the child process is launched, if the parent process goes ahead and changes some value (say, the "key" in the example above), the child process would see it? This is on linux. Essentially, is singleton behavior preserved in child processes also? – coder Aug 30 '18 at 16:13
  • I wrote up an answer that hopefully (?!) explains how it works. – tdelaney Aug 30 '18 at 16:34

1 Answers1

0

On forking systems, child processes have a copy on write view of the parent memory space. Processes use virtual memory and right after the fork both process virtual spaces point to the same physical RAM. On write, the physical page is copied and virtual memory is remapped so that bit of the the memory is no longer shared. This deferred copy is usually faster than cloning the memory space at the fork.

The result is that neither parent or child sees the other sides changes. Since you setup the singleton before the fork, both parent and child see the same value.

Here is a quick example where I use time.sleep to control when parent and child make their private changes:

import multiprocessing as mp
import time

def proc():
    global foo
    time.sleep(1)
    print('child foo should be 1, the value before the fork:', foo)
    foo = 3 # child private copy


foo = 1 # the value both see at fork
p = mp.Process(target=proc)
p.start()
foo = 2 # parent private copy
time.sleep(2)
print('parent foo should be 2, not the 3 set by child:', foo)

When run:

child foo should be 1, the value before the fork: 1
parent foo should be 2, not the 3 set by child: 2
tdelaney
  • 73,364
  • 6
  • 83
  • 116