Issue #18999: Make multiprocessing use context objects.

This allows different parts of a program to use different methods for
starting processes without interfering with each other.
diff --git a/Lib/multiprocessing/sharedctypes.py b/Lib/multiprocessing/sharedctypes.py
index a97dadf..0c17825 100644
--- a/Lib/multiprocessing/sharedctypes.py
+++ b/Lib/multiprocessing/sharedctypes.py
@@ -11,10 +11,10 @@
 import weakref
 
 from . import heap
+from . import get_context
 
-from .synchronize import RLock
+from .context import assert_spawning
 from .reduction import ForkingPickler
-from .popen import assert_spawning
 
 __all__ = ['RawValue', 'RawArray', 'Value', 'Array', 'copy', 'synchronized']
 
@@ -66,7 +66,7 @@
         result.__init__(*size_or_initializer)
         return result
 
-def Value(typecode_or_type, *args, lock=True):
+def Value(typecode_or_type, *args, lock=True, ctx=None):
     '''
     Return a synchronization wrapper for a Value
     '''
@@ -74,12 +74,13 @@
     if lock is False:
         return obj
     if lock in (True, None):
-        lock = RLock()
+        ctx = ctx or get_context()
+        lock = ctx.RLock()
     if not hasattr(lock, 'acquire'):
         raise AttributeError("'%r' has no method 'acquire'" % lock)
-    return synchronized(obj, lock)
+    return synchronized(obj, lock, ctx=ctx)
 
-def Array(typecode_or_type, size_or_initializer, *, lock=True):
+def Array(typecode_or_type, size_or_initializer, *, lock=True, ctx=None):
     '''
     Return a synchronization wrapper for a RawArray
     '''
@@ -87,25 +88,27 @@
     if lock is False:
         return obj
     if lock in (True, None):
-        lock = RLock()
+        ctx = ctx or get_context()
+        lock = ctx.RLock()
     if not hasattr(lock, 'acquire'):
         raise AttributeError("'%r' has no method 'acquire'" % lock)
-    return synchronized(obj, lock)
+    return synchronized(obj, lock, ctx=ctx)
 
 def copy(obj):
     new_obj = _new_value(type(obj))
     ctypes.pointer(new_obj)[0] = obj
     return new_obj
 
-def synchronized(obj, lock=None):
+def synchronized(obj, lock=None, ctx=None):
     assert not isinstance(obj, SynchronizedBase), 'object already synchronized'
+    ctx = ctx or get_context()
 
     if isinstance(obj, ctypes._SimpleCData):
-        return Synchronized(obj, lock)
+        return Synchronized(obj, lock, ctx)
     elif isinstance(obj, ctypes.Array):
         if obj._type_ is ctypes.c_char:
-            return SynchronizedString(obj, lock)
-        return SynchronizedArray(obj, lock)
+            return SynchronizedString(obj, lock, ctx)
+        return SynchronizedArray(obj, lock, ctx)
     else:
         cls = type(obj)
         try:
@@ -115,7 +118,7 @@
             d = dict((name, make_property(name)) for name in names)
             classname = 'Synchronized' + cls.__name__
             scls = class_cache[cls] = type(classname, (SynchronizedBase,), d)
-        return scls(obj, lock)
+        return scls(obj, lock, ctx)
 
 #
 # Functions for pickling/unpickling
@@ -175,9 +178,13 @@
 
 class SynchronizedBase(object):
 
-    def __init__(self, obj, lock=None):
+    def __init__(self, obj, lock=None, ctx=None):
         self._obj = obj
-        self._lock = lock or RLock()
+        if lock:
+            self._lock = lock
+        else:
+            ctx = ctx or get_context(force=True)
+            self._lock = ctx.RLock()
         self.acquire = self._lock.acquire
         self.release = self._lock.release