Skip to main content

Modules/_multiprocessing/

Source:

cpython 3.14 @ ab2d84fe1023/Modules/_multiprocessing/semaphore.c

_multiprocessing provides OS primitives that multiprocessing needs but that Python's threading module does not expose. The main components are SemLock (semaphore-based mutex/event) and Connection (socket or pipe IPC).

Map

LinesSymbolRole
1-100SemLock typePOSIX named/unnamed semaphore or Win32 CreateSemaphore
101-300SemLock_acquireBlock until acquired, with optional timeout
301-500SemLock_releaseRelease the semaphore
501-700SemLock__rebuildRe-open a named semaphore by handle in a new process
701-900Recursive/non-recursive lockSupports RLock (recursion count) vs plain Lock
901-1200Module initmultiprocessing top-level helpers

Reading

SemLock creation

// CPython: Modules/_multiprocessing/semaphore.c:65 semlock_new
static PyObject *
semlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
SEM_HANDLE handle;
#ifdef POSIX_SEMAPHORES_NOT_ENABLED
/* Fall back to POSIX named semaphores */
char name[SEM_NAME_LEN];
PyOS_snprintf(name, SEM_NAME_LEN, "/mp%d-%zd", getpid(), ...);
handle = sem_open(name, O_CREAT | O_EXCL, 0600, value);
sem_unlink(name); /* immediately unlink so it auto-deletes */
#else
/* POSIX unnamed semaphores (faster, no file system entry) */
sem_t *sem = (sem_t *)PyMem_Malloc(sizeof(sem_t));
sem_init(sem, 0, value);
handle = sem;
#endif
...
}

acquire with timeout

// CPython: Modules/_multiprocessing/semaphore.c:185 semlock_acquire
static PyObject *
semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds)
{
int block = 1;
double timeout = 0.0;
/* block=False: sem_trywait */
if (!block) {
res = sem_trywait(self->handle);
return res == 0 ? Py_True : Py_False;
}
/* timeout: sem_timedwait with absolute deadline */
if (timeout > 0.0) {
struct timespec deadline;
clock_gettime(CLOCK_REALTIME, &deadline);
deadline.tv_sec += (time_t)timeout;
deadline.tv_nsec += (long)((timeout - (time_t)timeout) * 1e9);
Py_BEGIN_ALLOW_THREADS
res = sem_timedwait(self->handle, &deadline);
Py_END_ALLOW_THREADS
} else {
Py_BEGIN_ALLOW_THREADS
res = sem_wait(self->handle);
Py_END_ALLOW_THREADS
}
...
}

Cross-process handle sharing

// CPython: Modules/_multiprocessing/semaphore.c:580 semlock__rebuild
static PyObject *
semlock__rebuild(PyTypeObject *type, PyObject *args)
{
/* Re-attach to a semaphore by its name or handle, in a child process */
/* Used by ForkingPickler to serialize Lock/Semaphore across fork/spawn */
SEM_HANDLE handle = (SEM_HANDLE)h;
...
}

When a multiprocessing.Lock is passed to a child process via spawn (not fork), it is serialized by handle and re-opened in the child.

gopy notes

multiprocessing is not in gopy's current scope. The annotation covers the C layer for reference. In Go, inter-process communication would use os/exec + channels, shared memory via mmap, or Unix domain sockets. The SemLock primitives map to sync.Mutex/sync.Cond for in-process use, or OS-specific semaphore wrappers for cross-process use.