This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Maybe can not shutdown ThreadPoolExecutor when call the method of shutdown
Type: behavior Stage:
Components: Library (Lib) Versions: Python 3.4, Python 3.5, Python 2.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: josh.r, miles, milesli
Priority: normal Keywords: patch

Created on 2015-02-03 08:20 by miles, last changed 2022-04-11 14:58 by admin.

Files
File name Uploaded Description Edit
thread.py miles, 2015-02-03 09:30
thread.py miles, 2015-02-03 11:12
thread.py.patch milesli, 2015-02-28 07:05 the patch of thread.py
Messages (6)
msg235319 - (view) Author: miles (miles) Date: 2015-02-03 08:20
Maybe can not shutdown ThreadPoolExecutor when call the method shutdown.

Though the variable of _shutdown is set to true in the method of shutdown, it may also reads the variable of _shutdown from cpu cache in the method of _worker, and the worst case is that it could see an out-of-date value of _shutdown forever. so need to acquire lock before reading the variable of _shutdown to make sure see an up-to-date value.


the following is the new code:



def _worker(executor_reference, work_queue):
    try:
        while True:
            work_item = work_queue.get(block=True)
            if work_item is not None:
                work_item.run()
                continue
            executor = executor_reference()
            
            shutdown = False
            with executor._shutdown_lock.acquire():
                shutdown = executor._shutdown
            
            # Exit if:
            #   - The interpreter is shutting down OR
            #   - The executor that owns the worker has been collected OR
            #   - The executor that owns the worker has been shutdown.
            if _shutdown or executor is None or shutdown:
                # Notice other workers
                work_queue.put(None)
                return
            del executor
    except BaseException:
        _base.LOGGER.critical('Exception in worker', exc_info=True)




    def shutdown(self, wait=True):
        with self._shutdown_lock:
            self._shutdown = True
            self._work_queue.put(None)
        if wait:
            for t in self._threads:
                t.join()
msg235325 - (view) Author: miles (miles) Date: 2015-02-03 09:30
The attachment includes the new code
msg235337 - (view) Author: miles (miles) Date: 2015-02-03 11:12
the attachment includes the new code
msg236643 - (view) Author: Mark Lawrence (BreamoreBoy) * Date: 2015-02-26 02:31
@Miles could you provide the code changes as a unified diff file, and if needed any changes to the test code as well, thanks.
msg236869 - (view) Author: miles (milesli) * Date: 2015-02-28 07:05
The attachment includes the patch file
msg340436 - (view) Author: Josh Rosenberg (josh.r) * (Python triager) Date: 2019-04-17 19:03
Correct me if I'm wrong, but this isn't actually an issue for CPython, right? The GIL ensures that when a thread writes to _shutdown, nothing else is reading it until the GIL is released and acquired by a new thread (which synchronizes _shutdown).

It might conceivably be a problem on non-CPython interpreters if they have no other form of inter-thread synchronization involved; that said, the locking involved in the self.work_queue.get(block=True) call likely synchronizes by side-effect even there.
History
Date User Action Args
2022-04-11 14:58:12adminsetgithub: 67571
2019-04-17 19:03:42josh.rsetnosy: + josh.r
messages: + msg340436
2019-03-15 22:40:41BreamoreBoysetnosy: - BreamoreBoy
2015-02-28 07:05:26mileslisetfiles: + thread.py.patch

nosy: + milesli
messages: + msg236869

keywords: + patch
2015-02-26 02:31:57BreamoreBoysetversions: + Python 2.7, Python 3.4, Python 3.5, - Python 3.2
nosy: + BreamoreBoy

messages: + msg236643

components: + Library (Lib), - 2to3 (2.x to 3.x conversion tool)
type: behavior
2015-02-03 11:12:45milessetfiles: + thread.py

messages: + msg235337
2015-02-03 09:30:37milessetfiles: + thread.py

messages: + msg235325
2015-02-03 08:20:03milescreate