Source code for katharos.concurrency.threading_backend

from __future__ import annotations

import threading
from typing import Any, Callable

from katharos.concurrency.base_threading_backend import (
    AbstractCondition,
    AbstractLock,
    BaseThreadHandle,
    BaseThreadingBackend,
)


[docs] class ThreadingHandle(BaseThreadHandle): """A :class:`BaseThreadHandle` backed by a :class:`threading.Thread`."""
[docs] def __init__(self, thread: threading.Thread) -> None: """Wrap an already-started thread. Args: thread: The running thread this handle refers to. """ self._thread = thread
[docs] def join(self, timeout: float | None = None) -> None: """Block until the underlying thread finishes (or ``timeout`` elapses). Args: timeout: Maximum seconds to wait, or ``None`` to wait forever. """ self._thread.join(timeout)
[docs] def is_alive(self) -> bool: """Return whether the underlying thread is still running. Returns: ``True`` while the thread is running, ``False`` once it finishes. """ return self._thread.is_alive()
[docs] class ThreadingBackend(BaseThreadingBackend): """A threading backend built on the standard library :mod:`threading`. This is the default backend used by Katharos' concurrency types. Spawned work runs on daemon :class:`threading.Thread` instances, and the synchronization primitives are plain :class:`threading.Lock` and :class:`threading.Condition` objects. """
[docs] def spawn(self, fn: Callable[[], Any]) -> ThreadingHandle: """Run ``fn`` on a new daemon thread. Args: fn: The zero-argument callable to run. Its return value is ignored. Returns: A :class:`ThreadingHandle` for the started thread. """ thread = threading.Thread(target=fn, daemon=True) thread.start() return ThreadingHandle(thread)
[docs] def create_lock(self) -> AbstractLock: """Create a new :class:`threading.Lock`. Returns: A standard-library lock. """ return threading.Lock()
[docs] def create_condition(self) -> AbstractCondition: """Create a new :class:`threading.Condition`. Returns: A standard-library condition variable. """ return threading.Condition()
[docs] def create_local(self) -> threading.local: """Create a new :class:`threading.local`. Returns: Standard-library thread-local storage, isolated per OS thread. """ return threading.local()
_default_backend = ThreadingBackend()
[docs] def default_backend() -> ThreadingBackend: """Return the shared default threading backend. Consumers that are not given an explicit backend use this one. The instance is stateless and safe to share across threads. Returns: The process-wide default :class:`ThreadingBackend`. """ return _default_backend