Change RLock from factory function to actual type, remove dead Python RLock implementation
Feature or enhancement
Proposal:
Currently in CPython threading.RLock is a factory function that returns a new RLock instance. It either returns an instance of _CRLock, if it's defined, otherwise it returns an instance of _PyRLock. I'm kidding--in practice, it never returns _PyRLock. You'd have to do something silly (threading._CRLock = None) in order to get it to return an instance of _PyRLock, because these days _CRLock is always defined.
I haven't gone reading through old versions / git blame / etc, but my guess is that CPython used to support platforms that didn't have a native RLock, or the C implementation of RLock was unsuitable for some reason on some platforms. Here in 2025 I find the C implementation of RLock is unguarded by any #if / #ifdef statement. All platforms currently supported by CPython must support threading, the C version of RLock (_thread.RLock) is always defined, and the threading.RLock factory function always returns an instance of that object (unless you do something silly).
Assuming I'm right about all that:
- The Python implementation of RLock (
class _RLock) inLib/threading.pyis dead code and should be removed. - There's no longer any point in making
threading.RLocka factory function. (Was there ever a point?)threading.RLockshould simply be an alias for the RLock implementation in C (_thread.RLock).
Has this already been discussed elsewhere?
No response given
Links to previous discussion of this feature:
No response
Linked PRs
- gh-141462
IMO, it sounds good.
And I'd like to add something on related topic.
Today I've realized that _thread.lock can not be used as base type, but _thread.RLock can be used.
Is it intentional?
>>> import _thread
>>> class C(_thread.lock): pass
...
Traceback (most recent call last):
File "<python-input-54>", line 1, in <module>
class C(_thread.lock): pass
TypeError: type '_thread.lock' is not an acceptable base type
>>> class C(_thread.RLock): pass
...
>>>
IMO, it sounds good.
And I'd like to add something on related topic. Today I've realized that
_thread.lockcan not be used as base type, but_thread.RLockcan be used. Is it intentional?import _thread class C(_thread.lock): pass ... Traceback (most recent call last): File "
", line 1, in class C(_thread.lock): pass TypeError: type '_thread.lock' is not an acceptable base type class C(_thread.RLock): pass ...
I might be wrong, but I think _thread.lock is defined in without Py_TPFLAGS_BASETYPE (and with Py_TPFLAGS_IMMUTABLETYPE), so it’s not subclassable. It’s meant to be a minimal, fast primitive with tight invariants. On the other hand _thread.RLock is defined with Py_TPFLAGS_BASETYPE, so it is subclassable. It also exposes the private hooks (_acquire_restore, _release_save, _recursion_count, _is_owned, _at_fork_reinit) that threading.Condition uses.
Py_TPFLAGS_BASETYPE
I found this commit: https://github.com/python/cpython/pull/114479/commits/b33a71ae609385d5e368ab98088ca2f0e6cf6aa9
# Intentionally disallow subclasses of threading.Lock because they have
# never been allowed, so why start now just because the type is public?
So that it's intentional.
I'll raise a PR to remove dead RLock code.