Kyle Stanley <aeros...@gmail.com> added the comment:

I spent some further time considering the solution to the problem, and I still 
think something like a `threading.register_atexit()` (see 
https://bugs.python.org/issue37266#msg362960) would be the most suitable.

However, I'm not certain regarding the exact details. The simplest pure Python 
implementation I can think of would be through a global list in 
`Lib/threading.py`, which is only initialized when 
`threading.register_atexit()` is called for the first time (to avoid unneeded 
overhead when threading exit functions aren't needed). In order to preserve 
keyword arguments, each registered function would be appended to the list as a 
partial. Then, in the private `_shutdown()`, each registered atexit function is 
called just after the main thread is finished, but just before the non-daemon 
threads are joined:

```
_threading_atexits = None

def register_atexit(func, *args, **kwargs):
    global _threading_atexits
    if _threading_atexits is None:
        _threading_atexits = []
    call = functools.partial(func, *args, **kwargs)
    _threading_atexits.append(call)

# [snip]

def _shutdown():
    if _main_thread._is_stopped:
        # _shutdown() was already called
        return

    # Main thread
    tlock = _main_thread._tstate_lock
    # The main thread isn't finished yet, so its thread state lock can't have
    # been released.
    assert tlock is not None
    assert tlock.locked()
    tlock.release()
    _main_thread._stop()
    
    # Call registered threading atexit functions
    for atexit_call in _threading_atexits:
        atexit_call()

    # Join all non-deamon threads
    # [snip]
```

Could something like the above pure Python implementation be adequate for our 
purposes? It seems like it would be to me, but I could very well be missing 
something. I'll of course have to test if it works as intended for replacing 
the daemon threads in concurrent.futures.

Another factor to consider is whether or not something like this would be 
widely useful enough to consider adding `threading.register_atexit()` to the 
public API for the threading module, or if it should just be an internal 
_function with a docstring. I could see it being useful in similar cases where 
daemon threads are no longer a viable option (due to subinterepter 
compatibility or any other reason). But, I suspect the demand for it won't be 
overly high from users until PEP 554 is completed.

Thoughts?

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue39812>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to