Skip to main content

Python/thread.c

Source:

cpython 3.14 @ ab2d84fe1023/Python/thread.c

Python/thread.c is the platform-independent dispatcher for the low-level thread API. The actual OS calls are in Python/thread_pthread.h (POSIX) or Python/thread_nt.h (Windows).

Map

LinesSymbolRole
1-100PyThread_start_new_threadLaunch a new OS thread
101-250PyThread_allocate_lock, acquire_timed, releaseMutex operations
251-400PyThread_get_ident, PyThread_get_thread_native_idThread identity
401-600PyThread_exit_thread, PyThread_daemon_threads_allowedLifecycle
601-800PyThread_tss_*Thread-specific storage (PEP 539)

Reading

Starting a thread

// CPython: Python/thread.c:58 PyThread_start_new_thread
unsigned long
PyThread_start_new_thread(void (*func)(void *), void *arg)
{
/* Delegates to thread_pthread.h: pthread_create */
pthread_t th;
pthread_attr_t attrs;
pthread_attr_init(&attrs);
if (tls_key != 0)
pthread_attr_setstacksize(&attrs, ...);
int status = pthread_create(&th, &attrs, (void *(*)(void *))func, arg);
...
return (unsigned long)th;
}

func is a C wrapper that calls the Python-level target after acquiring the GIL.

Lock acquisition with timeout

// CPython: Python/thread.c:180 acquire_timed
static PyLockStatus
acquire_timed(sem_t *lock, _PyTime_t timeout)
{
/* Loop until acquired or timed out */
while (1) {
int r;
if (timeout > 0) {
struct timespec ts = ...;
r = sem_timedwait(lock, &ts);
} else {
r = sem_wait(lock);
}
if (r == 0)
return PY_LOCK_ACQUIRED;
if (errno == EINTR)
continue; /* retry on signal */
if (errno == ETIMEDOUT)
return PY_LOCK_FAILURE;
}
}

Thread-specific storage (PEP 539)

// CPython: Python/thread.c:680 PyThread_tss_set
int
PyThread_tss_set(Py_tss_t *key, void *value)
{
return pthread_setspecific(*key, value) ? -1 : 0;
}

Py_tss_t wraps pthread_key_t. It replaced the older PyThread_set_key_value API in Python 3.7. Used internally by the decimal module and ctypes.

gopy notes

gopy maps Python threads to goroutines. PyThread_start_new_thread calls go func(). PyThread_allocate_lock returns a sync.Mutex wrapper. PyThread_get_ident returns a goroutine ID (obtained via runtime stack introspection or an atomic counter). Thread-specific storage maps to goroutine-local context via sync.Map.