loop.call_soon_threadsafe 1 is a thread safe API to schedule callbacks from other threads however the handle returned by it i.e. asyncio.Handle 2 isn't thread safe like its cancel 3 method. This is an issue even with the GIL because thread switching is preemptive and is a bigger issue for free-threading builds.
Proposal
Add a new _ThreadSafeHandle which inherits from asyncio.Handle but internally uses a mutex to avoid multiple threads cancelling and running the callback at the same time for callbacks scheduled by loop.call_soon_threadsafe API, other APIs such as loop.call_soon will continue to use the old asyncio.Handle.
Linked PRs
loop.call_soon_threadsafe1 is a thread safe API to schedule callbacks from other threads however the handle returned by it i.e.asyncio.Handle2 isn't thread safe like itscancel3 method. This is an issue even with the GIL because thread switching is preemptive and is a bigger issue for free-threading builds.Proposal
Add a new
_ThreadSafeHandlewhich inherits fromasyncio.Handlebut internally uses a mutex to avoid multiple threads cancelling and running the callback at the same time for callbacks scheduled byloop.call_soon_threadsafeAPI, other APIs such asloop.call_soonwill continue to use the oldasyncio.Handle.Linked PRs
loop.call_soon_threadsafe#128369Footnotes
https://docs.python.org/3.13/library/asyncio-eventloop.html#asyncio.loop.call_soon_threadsafe ↩
https://docs.python.org/3.13/library/asyncio-eventloop.html#asyncio.Handle ↩
https://docs.python.org/3.13/library/asyncio-eventloop.html#asyncio.Handle.cancel ↩