Author aeros
Recipients aeros, pitrou, tomMoral
Date 2020-03-08.00:53:32
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1583628813.13.0.241630321771.issue39812@roundup.psfhosted.org>
In-reply-to
Content
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?
History
Date User Action Args
2020-03-08 00:53:33aerossetrecipients: + aeros, pitrou, tomMoral
2020-03-08 00:53:33aerossetmessageid: <1583628813.13.0.241630321771.issue39812@roundup.psfhosted.org>
2020-03-08 00:53:33aeroslinkissue39812 messages
2020-03-08 00:53:32aeroscreate