[1.0 Decision] Document the threading contract: mcrfpy.lock() is the rule for off-main-thread access #327

Closed
opened 2026-07-02 12:29:36 +00:00 by john · 0 comments
Owner

From the 2026-07-02 pre-1.0 memory-model review. The promise freezes at 1.0; the implementation can harden afterward.

What exists

The engine already has a deliberate concurrency design (#219):

  • mcrfpy.lock() -> PyLockContext (src/PyLock.cpp): no-op on the main thread; on worker threads blocks (GIL released) until the main loop opens a safe window via FrameLock (src/GameEngine.cpp:34-36, 493-499).
  • GIL is released around display() (src/GameEngine.cpp:477-498) so worker threads get scheduled every frame.
  • All engine->Python callbacks re-acquire via PyGILState_Ensure (src/Animation.cpp:707-770, src/PySceneObject.cpp:352-400).

What's missing

A normative statement in the docs: any access to mcrfpy objects from a non-main thread must happen inside with mcrfpy.lock():; behavior outside the lock is undefined. This coarse-grained contract works identically under GIL and free-threaded builds, and it is the promise that makes the free-threading hardening work (#336) tractable -- the engine never has to become internally thread-safe.

Deliverables

  • Docs page on the threading model (main loop, FrameLock windows, worker-thread pattern with example).
  • mcrfpy.lock() docstring stating the contract (MCRF_* macros).
  • One line in the API reference intro.

Related: #220 (subinterpreters are the other concurrency model, deferred).

From the 2026-07-02 pre-1.0 memory-model review. **The promise freezes at 1.0; the implementation can harden afterward.** ## What exists The engine already has a deliberate concurrency design (#219): - `mcrfpy.lock()` -> `PyLockContext` (`src/PyLock.cpp`): no-op on the main thread; on worker threads blocks (GIL released) until the main loop opens a safe window via `FrameLock` (`src/GameEngine.cpp:34-36, 493-499`). - GIL is released around `display()` (`src/GameEngine.cpp:477-498`) so worker threads get scheduled every frame. - All engine->Python callbacks re-acquire via `PyGILState_Ensure` (`src/Animation.cpp:707-770`, `src/PySceneObject.cpp:352-400`). ## What's missing A **normative statement** in the docs: *any access to mcrfpy objects from a non-main thread must happen inside `with mcrfpy.lock():`; behavior outside the lock is undefined.* This coarse-grained contract works identically under GIL and free-threaded builds, and it is the promise that makes the free-threading hardening work (#336) tractable -- the engine never has to become internally thread-safe. ## Deliverables - Docs page on the threading model (main loop, FrameLock windows, worker-thread pattern with example). - `mcrfpy.lock()` docstring stating the contract (MCRF_* macros). - One line in the API reference intro. Related: #220 (subinterpreters are the *other* concurrency model, deferred).
john closed this issue 2026-07-03 03:45:58 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
john/McRogueFace#327
No description provided.