Sharing a record between processes¶
In this tutorial you build a small script in which two processes share one
record: the first creates it, the second changes a value in it, and the
first reads the change. Such a record is a box, and on the way
you meet the three calls you will use most: create, attach and close.
Before you start¶
What you need
Python 3.11 or newer on Windows or Linux, and
uv.
Make a project folder and add sharedbox to it:
In the folder, create an empty file called motor.py and start it with
these imports:
import multiprocessing as mp
import queue
import time
from typing import Annotated
from sharedbox import Capacity, SharedBox
You won't need queue and time until the
third tutorial, but adding them now saves you
coming back to this line.
1. Define the record¶
Below the imports, describe the record as a class:
class Motor(SharedBox):
position: int = 0
enabled: bool = False
label: Annotated[str, Capacity(32)] = ""
This reads like a dataclass, and it works like one: each annotated
attribute is a field, and the value after = is its default.
The difference is that Motor subclasses
SharedBox, so its fields live in shared memory
instead of inside one Python object.
Text needs a size limit, its capacity: label holds at most
32 bytes. Every field has a fixed size so that all processes agree on where
each value sits; How a box is stored
explains why that matters.
2. Change it from another process¶
Next, add the function the second process will run. It opens the box, writes one field and lets go:
def move(position: int) -> None:
motor = Motor.attach("tutorial-motor")
motor.position = position
motor.close()
attach opens the box named
tutorial-motor, which the first process creates in the next step. Setting
motor.position writes the new value straight into shared memory, where
every process can see it. close then drops
this process's handle on the box, and the box itself stays
for the processes still using it.
3. Create the box¶
Now add the function the first process runs. It creates the box, starts the second process and reads what that process wrote:
def share() -> None:
with Motor.create("tutorial-motor", label="x-axis") as motor:
other = mp.Process(target=move, args=(10,))
other.start()
other.join()
print("position set by the other process:", motor.position)
Motor.unlink("tutorial-motor")
create puts the box in a new
segment of shared memory under the name you give it. It
takes field values the way calling the class does, so here you set label
and leave position and enabled at their defaults.
The second process runs move(10). Once join returns, that process has
finished, so reading motor.position finds the value it wrote.
When the with block ends it closes the box, and
unlink removes the name, so the next run
can create the box again. How to name a box
shows other ways to choose a name.
4. Run it¶
Add these lines at the end of the file:
You need them because, depending on your system, the second process starts a
fresh Python that imports your script to find move. Without the if, that
import would call share() again and try to create the box a second time.
Now run the script:
You should see:
What you built¶
You have a record in shared memory that two processes read and write: the
first created it, the second changed position, and the first read the
new value.
Next steps¶
- Reacting to changes is next: instead of reading the value after the other process ends, the first process sees each change the moment it happens.
- How a box is stored shows what the shared memory holds.
SharedBoxlists every type a field can have.