The objective of POSH is to allow regular Python objects to reside in shared memory, where they can be made accessible to multiple concurrent processes. Objects allocated in shared memory are referred to as shared objects. For convenience, the types of shared objects are referred to as shared types, even though the actual type objects are not allocated in shared memory. Since type objects are essentially read-only data structures, the shared types can easily be made accessible to all processes by creating them prior to any fork() calls.
The process of creating a shared object that is a copy of a given non-shared object, is referred to as sharing the object. Objects that are eligible for sharing are called shareable objects, and their types are referred to as shareable types. POSH maintains a mapping that specifies the correspondence between shareable and shared types.
When an object is shared, its type is mapped to the corresponding shared type, and an instance of the shared type is created, which copies its initial value from the object being shared. The basic strategy for implementing a shared type is to subtype its equivalent shareable type, overriding its allocation methods. This allows the shared type to inherit the existing implementation details of the shareable type, while overriding the crucial aspect of object allocation.
An exception to this rule are the shared container types, which are reimplemented from scratch by POSH. Recursive data structures generally cannot be stored in shared memory using regular pointers, since shared memory regions can be attached at different virtual addresses in different processes. POSH uses an alternative abstraction, memory handles, to refer to locations in shared memory in a manner that is unambiguous to all processes. Shareable versions of the standard container types are implemented using this abstraction. Section 2.1 goes into more detail about memory handles.
For objects that are accessible to multiple concurrent processes, the regular garbage collection algorithm used by Python is inadequate. POSH implements a separate garbage collection algorithm for shared objects. In the event of abnormal process terminations, the algorithm allows the reference counts of shared objects to be corrected accordingly. Since the Python interpreter is unaware of the garbage collection algorithm used for shared objects, POSH wraps all shared objects in special proxy objects to shield them from direct reference. Section 2.2 describes proxy objects and the garbage collection algorithm implemented by POSH.
Shared objects are never made directly accessible to Python code; they are always accessed by means of their proxy objects. This provides a single access point to shared objects, which allows POSH to enforce synchronization policies for shared objects in a transparent manner. For instance, monitor access semantics can be enforced implicitly whenever a shared object is accessed. Section 2.3 describes how POSH handles synchronization.