Source code for tango.utils._concurrency
# SPDX-FileCopyrightText: All Contributors to the PyTango project
# SPDX-License-Identifier: LGPL-3.0-or-later
"""Threads and pools that register themselves with omniORB."""
import threading
import weakref
# Since cppTango based on omniThreads, we have to slightly modify ThreadPoolExecutor,
# to use threads with ensured dummy omniORB ID
#
# The `_adjust_thread_count` method below is a slightly modified version of the code from
# https://github.com/python/cpython/blob/3.12/Lib/concurrent/futures/thread.py
# and
# https://github.com/python/cpython/blob/3.14/Lib/concurrent/futures/thread.py
# Copyright (c) Python Software Foundation; All Rights Reserved
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures.thread import _threads_queues, _worker
from tango import EnsureOmniThread
[docs]
class PyTangoThreadPoolExecutor(ThreadPoolExecutor):
"""
Based on :class:`concurrent.futures.ThreadPoolExecutor`,
but additionally ensures every running thread is a dummy omniORB thread.
The :class:`tango.EnsureOmniThread` context handler is automatically active for
the lifetime of the all the thread pool's threads.
.. versionadded:: 10.0.0
"""
def _adjust_thread_count(self):
# if idle threads are available, don't spin new threads
if self._idle_semaphore.acquire(timeout=0):
return
# When the executor gets lost, the weakref callback will wake up
# the worker threads.
def weakref_cb(_, q=self._work_queue):
q.put(None)
num_threads = len(self._threads)
if num_threads < self._max_workers:
thread_name = f"{self._thread_name_prefix or self}_{num_threads}"
if hasattr(self, "_initializer"):
# Python < 3.14
t = threading.Thread(
name=thread_name,
target=_thread_pool_executor_worker,
args=(
weakref.ref(self, weakref_cb),
self._work_queue,
self._initializer,
self._initargs,
),
)
else:
# Python >= 3.14
t = threading.Thread(
name=thread_name,
target=_thread_pool_executor_ctx_worker,
args=(
weakref.ref(self, weakref_cb),
self._create_worker_context(),
self._work_queue,
),
)
t.start()
self._threads.add(t)
_threads_queues[t] = self._work_queue
# Override _worker for Python < 3.14
def _thread_pool_executor_worker(executor_reference, work_queue, initializer, initargs):
with EnsureOmniThread():
_worker(executor_reference, work_queue, initializer, initargs)
# Override _worker for Python >= 3.14
def _thread_pool_executor_ctx_worker(executor_reference, ctx, work_queue):
with EnsureOmniThread():
_worker(executor_reference, ctx, work_queue)
[docs]
class PyTangoThread(threading.Thread):
"""
Based on :class:`threading.Thread`, but additionally ensures it is a dummy omniORB thread.
The :class:`tango.EnsureOmniThread` handler is automatically active for the lifetime of the
thread.
.. versionadded:: 10.3.0
"""
def _bootstrap_inner(self):
with EnsureOmniThread():
super()._bootstrap_inner()