bpo-36084: Add native thread ID to threading.Thread objects (GH-11993)
diff --git a/Lib/_dummy_thread.py b/Lib/_dummy_thread.py
index a2cae54..0a877e1 100644
--- a/Lib/_dummy_thread.py
+++ b/Lib/_dummy_thread.py
@@ -71,6 +71,10 @@
"""
return 1
+def get_native_id():
+ """Dummy implementation of _thread.get_native_id()."""
+ return 0
+
def allocate_lock():
"""Dummy implementation of _thread.allocate_lock()."""
return LockType()
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
index 2ddc77b..6ac6e9d 100644
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -104,6 +104,10 @@
self.assertRegex(repr(t), r'^<TestThread\(.*, initial\)>$')
t.start()
+ native_ids = set(t.native_id for t in threads) | {threading.get_native_id()}
+ self.assertNotIn(None, native_ids)
+ self.assertEqual(len(native_ids), NUMTASKS + 1)
+
if verbose:
print('waiting for all tasks to complete')
for t in threads:
diff --git a/Lib/threading.py b/Lib/threading.py
index 0ebbd67..3137e49 100644
--- a/Lib/threading.py
+++ b/Lib/threading.py
@@ -23,8 +23,8 @@
# with the multiprocessing module, which doesn't provide the old
# Java inspired names.
-__all__ = ['get_ident', 'active_count', 'Condition', 'current_thread',
- 'enumerate', 'main_thread', 'TIMEOUT_MAX',
+__all__ = ['get_ident', 'get_native_id', 'active_count', 'Condition',
+ 'current_thread', 'enumerate', 'main_thread', 'TIMEOUT_MAX',
'Event', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', 'Thread',
'Barrier', 'BrokenBarrierError', 'Timer', 'ThreadError',
'setprofile', 'settrace', 'local', 'stack_size']
@@ -34,6 +34,7 @@
_allocate_lock = _thread.allocate_lock
_set_sentinel = _thread._set_sentinel
get_ident = _thread.get_ident
+get_native_id = _thread.get_native_id
ThreadError = _thread.error
try:
_CRLock = _thread.RLock
@@ -790,6 +791,7 @@
else:
self._daemonic = current_thread().daemon
self._ident = None
+ self._native_id = 0
self._tstate_lock = None
self._started = Event()
self._is_stopped = False
@@ -891,6 +893,9 @@
def _set_ident(self):
self._ident = get_ident()
+ def _set_native_id(self):
+ self._native_id = get_native_id()
+
def _set_tstate_lock(self):
"""
Set a lock object which will be released by the interpreter when
@@ -903,6 +908,7 @@
try:
self._set_ident()
self._set_tstate_lock()
+ self._set_native_id()
self._started.set()
with _active_limbo_lock:
_active[self._ident] = self
@@ -1077,6 +1083,17 @@
assert self._initialized, "Thread.__init__() not called"
return self._ident
+ @property
+ def native_id(self):
+ """Native integral thread ID of this thread or 0 if it has not been started.
+
+ This is a non-negative integer. See the get_native_id() function.
+ This represents the Thread ID as reported by the kernel.
+
+ """
+ assert self._initialized, "Thread.__init__() not called"
+ return self._native_id
+
def is_alive(self):
"""Return whether the thread is alive.
@@ -1176,6 +1193,7 @@
self._set_tstate_lock()
self._started.set()
self._set_ident()
+ self._set_native_id()
with _active_limbo_lock:
_active[self._ident] = self
@@ -1195,6 +1213,7 @@
self._started.set()
self._set_ident()
+ self._set_native_id()
with _active_limbo_lock:
_active[self._ident] = self