33import os as _os
44import sys as _sys
55import _thread
6- import warnings
6+ import _contextvars
77
88from time import monotonic as _time
99from _weakrefset import WeakSet
4848 __all__ .append ('get_native_id' )
4949except AttributeError :
5050 _HAVE_THREAD_NATIVE_ID = False
51+ try :
52+ _set_name = _thread .set_name
53+ except AttributeError :
54+ _set_name = None
5155ThreadError = _thread .error
5256try :
5357 _CRLock = _thread .RLock
@@ -129,6 +133,7 @@ def RLock(*args, **kwargs):
129133
130134 """
131135 if args or kwargs :
136+ import warnings
132137 warnings .warn (
133138 'Passing arguments to RLock is deprecated and will be removed in 3.15' ,
134139 DeprecationWarning ,
@@ -160,7 +165,7 @@ def __repr__(self):
160165 except KeyError :
161166 pass
162167 return "<%s %s.%s object owner=%r count=%d at %s>" % (
163- "locked" if self ._block . locked () else "unlocked" ,
168+ "locked" if self .locked () else "unlocked" ,
164169 self .__class__ .__module__ ,
165170 self .__class__ .__qualname__ ,
166171 owner ,
@@ -237,6 +242,10 @@ def release(self):
237242 def __exit__ (self , t , v , tb ):
238243 self .release ()
239244
245+ def locked (self ):
246+ """Return whether this object is locked."""
247+ return self ._block .locked ()
248+
240249 # Internal methods used by condition variables
241250
242251 def _acquire_restore (self , state ):
@@ -282,9 +291,10 @@ def __init__(self, lock=None):
282291 if lock is None :
283292 lock = RLock ()
284293 self ._lock = lock
285- # Export the lock's acquire() and release () methods
294+ # Export the lock's acquire(), release(), and locked () methods
286295 self .acquire = lock .acquire
287296 self .release = lock .release
297+ self .locked = lock .locked
288298 # If the lock defines _release_save() and/or _acquire_restore(),
289299 # these override the default implementations (which just call
290300 # release() and acquire() on the lock). Ditto for _is_owned().
@@ -868,7 +878,7 @@ class Thread:
868878 _initialized = False
869879
870880 def __init__ (self , group = None , target = None , name = None ,
871- args = (), kwargs = None , * , daemon = None ):
881+ args = (), kwargs = None , * , daemon = None , context = None ):
872882 """This constructor should always be called with keyword arguments. Arguments are:
873883
874884 *group* should be None; reserved for future extension when a ThreadGroup
@@ -885,6 +895,14 @@ class is implemented.
885895 *kwargs* is a dictionary of keyword arguments for the target
886896 invocation. Defaults to {}.
887897
898+ *context* is the contextvars.Context value to use for the thread.
899+ The default value is None, which means to check
900+ sys.flags.thread_inherit_context. If that flag is true, use a copy
901+ of the context of the caller. If false, use an empty context. To
902+ explicitly start with an empty context, pass a new instance of
903+ contextvars.Context(). To explicitly start with a copy of the current
904+ context, pass the value from contextvars.copy_context().
905+
888906 If a subclass overrides the constructor, it must make sure to invoke
889907 the base class constructor (Thread.__init__()) before doing anything
890908 else to the thread.
@@ -914,10 +932,11 @@ class is implemented.
914932 self ._daemonic = daemon
915933 else :
916934 self ._daemonic = current_thread ().daemon
935+ self ._context = context
917936 self ._ident = None
918937 if _HAVE_THREAD_NATIVE_ID :
919938 self ._native_id = None
920- self ._handle = _ThreadHandle ()
939+ self ._os_thread_handle = _ThreadHandle ()
921940 self ._started = Event ()
922941 self ._initialized = True
923942 # Copy of sys.stderr used by self._invoke_excepthook()
@@ -932,7 +951,7 @@ def _after_fork(self, new_ident=None):
932951 if new_ident is not None :
933952 # This thread is alive.
934953 self ._ident = new_ident
935- assert self ._handle .ident == new_ident
954+ assert self ._os_thread_handle .ident == new_ident
936955 if _HAVE_THREAD_NATIVE_ID :
937956 self ._set_native_id ()
938957 else :
@@ -945,7 +964,7 @@ def __repr__(self):
945964 status = "initial"
946965 if self ._started .is_set ():
947966 status = "started"
948- if self ._handle .is_done ():
967+ if self ._os_thread_handle .is_done ():
949968 status = "stopped"
950969 if self ._daemonic :
951970 status += " daemon"
@@ -971,9 +990,19 @@ def start(self):
971990
972991 with _active_limbo_lock :
973992 _limbo [self ] = self
993+
994+ if self ._context is None :
995+ # No context provided
996+ if _sys .flags .thread_inherit_context :
997+ # start with a copy of the context of the caller
998+ self ._context = _contextvars .copy_context ()
999+ else :
1000+ # start with an empty context
1001+ self ._context = _contextvars .Context ()
1002+
9741003 try :
9751004 # Start joinable thread
976- _start_joinable_thread (self ._bootstrap , handle = self ._handle ,
1005+ _start_joinable_thread (self ._bootstrap , handle = self ._os_thread_handle ,
9771006 daemon = self .daemon )
9781007 except Exception :
9791008 with _active_limbo_lock :
@@ -1025,11 +1054,20 @@ def _set_ident(self):
10251054 def _set_native_id (self ):
10261055 self ._native_id = get_native_id ()
10271056
1057+ def _set_os_name (self ):
1058+ if _set_name is None or not self ._name :
1059+ return
1060+ try :
1061+ _set_name (self ._name )
1062+ except OSError :
1063+ pass
1064+
10281065 def _bootstrap_inner (self ):
10291066 try :
10301067 self ._set_ident ()
10311068 if _HAVE_THREAD_NATIVE_ID :
10321069 self ._set_native_id ()
1070+ self ._set_os_name ()
10331071 self ._started .set ()
10341072 with _active_limbo_lock :
10351073 _active [self ._ident ] = self
@@ -1041,7 +1079,7 @@ def _bootstrap_inner(self):
10411079 _sys .setprofile (_profile_hook )
10421080
10431081 try :
1044- self .run ()
1082+ self ._context . run (self . run )
10451083 except :
10461084 self ._invoke_excepthook (self )
10471085 finally :
@@ -1092,7 +1130,7 @@ def join(self, timeout=None):
10921130 if timeout is not None :
10931131 timeout = max (timeout , 0 )
10941132
1095- self ._handle .join (timeout )
1133+ self ._os_thread_handle .join (timeout )
10961134
10971135 @property
10981136 def name (self ):
@@ -1109,6 +1147,8 @@ def name(self):
11091147 def name (self , name ):
11101148 assert self ._initialized , "Thread.__init__() not called"
11111149 self ._name = str (name )
1150+ if get_ident () == self ._ident :
1151+ self ._set_os_name ()
11121152
11131153 @property
11141154 def ident (self ):
@@ -1143,7 +1183,7 @@ def is_alive(self):
11431183
11441184 """
11451185 assert self ._initialized , "Thread.__init__() not called"
1146- return self ._started .is_set () and not self ._handle .is_done ()
1186+ return self ._started .is_set () and not self ._os_thread_handle .is_done ()
11471187
11481188 @property
11491189 def daemon (self ):
@@ -1354,7 +1394,7 @@ def __init__(self):
13541394 Thread .__init__ (self , name = "MainThread" , daemon = False )
13551395 self ._started .set ()
13561396 self ._ident = _get_main_thread_ident ()
1357- self ._handle = _make_thread_handle (self ._ident )
1397+ self ._os_thread_handle = _make_thread_handle (self ._ident )
13581398 if _HAVE_THREAD_NATIVE_ID :
13591399 self ._set_native_id ()
13601400 with _active_limbo_lock :
@@ -1402,15 +1442,15 @@ def __init__(self):
14021442 daemon = _daemon_threads_allowed ())
14031443 self ._started .set ()
14041444 self ._set_ident ()
1405- self ._handle = _make_thread_handle (self ._ident )
1445+ self ._os_thread_handle = _make_thread_handle (self ._ident )
14061446 if _HAVE_THREAD_NATIVE_ID :
14071447 self ._set_native_id ()
14081448 with _active_limbo_lock :
14091449 _active [self ._ident ] = self
14101450 _DeleteDummyThreadOnDel (self )
14111451
14121452 def is_alive (self ):
1413- if not self ._handle .is_done () and self ._started .is_set ():
1453+ if not self ._os_thread_handle .is_done () and self ._started .is_set ():
14141454 return True
14151455 raise RuntimeError ("thread is not alive" )
14161456
@@ -1524,7 +1564,7 @@ def _shutdown():
15241564 # dubious, but some code does it. We can't wait for it to be marked as done
15251565 # normally - that won't happen until the interpreter is nearly dead. So
15261566 # mark it done here.
1527- if _main_thread ._handle .is_done () and _is_main_interpreter ():
1567+ if _main_thread ._os_thread_handle .is_done () and _is_main_interpreter ():
15281568 # _shutdown() was already called
15291569 return
15301570
@@ -1537,7 +1577,7 @@ def _shutdown():
15371577 atexit_call ()
15381578
15391579 if _is_main_interpreter ():
1540- _main_thread ._handle ._set_done ()
1580+ _main_thread ._os_thread_handle ._set_done ()
15411581
15421582 # Wait for all non-daemon threads to exit.
15431583 _thread_shutdown ()
0 commit comments