Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't gracefully ctrl+C multiprocessing pool on Python3 & Windows #82609

Open
rebeccafair mannequin opened this issue Oct 10, 2019 · 5 comments
Open

Can't gracefully ctrl+C multiprocessing pool on Python3 & Windows #82609

rebeccafair mannequin opened this issue Oct 10, 2019 · 5 comments
Labels
3.8 (EOL) end of life 3.9 only security fixes 3.10 only security fixes OS-windows topic-multiprocessing type-bug An unexpected behavior, bug, or error

Comments

@rebeccafair
Copy link
Mannequin

rebeccafair mannequin commented Oct 10, 2019

BPO 38428
Nosy @pfmoore, @pitrou, @tjguk, @zware, @eryksun, @zooba, @applio, @rebeccafair
Files
  • bug.py
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = None
    created_at = <Date 2019-10-10.08:35:51.894>
    labels = ['3.10', 'type-bug', '3.8', '3.9', 'OS-windows']
    title = "Can't gracefully ctrl+C multiprocessing pool on Python3 & Windows"
    updated_at = <Date 2021-03-22.03:12:37.354>
    user = 'https://github.com/rebeccafair'

    bugs.python.org fields:

    activity = <Date 2021-03-22.03:12:37.354>
    actor = 'eryksun'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['Windows']
    creation = <Date 2019-10-10.08:35:51.894>
    creator = 'rebeccafair'
    dependencies = []
    files = ['48653']
    hgrepos = []
    issue_num = 38428
    keywords = []
    message_count = 5.0
    messages = ['354344', '354346', '354393', '354413', '389273']
    nosy_count = 8.0
    nosy_names = ['paul.moore', 'pitrou', 'tim.golden', 'zach.ware', 'eryksun', 'steve.dower', 'davin', 'rebeccafair']
    pr_nums = []
    priority = 'normal'
    resolution = None
    stage = 'test needed'
    status = 'open'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue38428'
    versions = ['Python 3.8', 'Python 3.9', 'Python 3.10']

    @rebeccafair
    Copy link
    Mannequin Author

    rebeccafair mannequin commented Oct 10, 2019

    I want to be able to Ctrl+C to exit a multiprocessing Pool.map gracefully, and have made a solution based on this Stack Overflow answer: https://stackoverflow.com/questions/11312525/catch-ctrlc-sigint-and-exit-multiprocesses-gracefully-in-python

    However, this solution works on Linux, and on Windows 10 with Python 2.7, but not on Windows 10 with Python 3.7. The Ctrl+C is just ignored and I have to kill the processes manually. I've attached the minimum code required to reproduce the problem.

    Is this a bug, expected, or is there a workaround? I believe it might be caused by the behaviour of threading.Condition.wait() being changed in commit 7c3e577 but I don't know enough about signalling to say any more than that

    @rebeccafair rebeccafair mannequin added 3.7 (EOL) end of life OS-windows labels Oct 10, 2019
    @rebeccafair
    Copy link
    Mannequin Author

    rebeccafair mannequin commented Oct 10, 2019

    Sorry, I didn't realise it wouldn't link to a commit automatically, the commit is here: 7c3e577

    @zooba
    Copy link
    Member

    zooba commented Oct 10, 2019

    I think you're right about that change touching the right code, but I'm pretty sure it wasn't working before either. (Python 2.7 had totally different code, IIRC.)

    But the good news is that we should be able to use code similar to what's in Modules/timemodule.c#L1878 (the pysleep() function) to also wait on the event we use to emulate signals on Windows. But perhaps there's a reason Antoine (nosied) didn't do that originally?

    @zooba zooba added 3.8 (EOL) end of life 3.9 only security fixes type-bug An unexpected behavior, bug, or error labels Oct 10, 2019
    @eryksun
    Copy link
    Contributor

    eryksun commented Oct 10, 2019

    Python 2.7 had totally different code, IIRC.

    In 2.7 the wait() method of threading._Condition implements the timeout with a loop the calls time.sleep() with an increasing delay from 500 microseconds up to 50 ms, and no more than the remaining time.

    But the good news is that we should be able to use code similar to
    what's in Modules/timemodule.c#L1878 (the pysleep() function) to also
    wait on the event we use to emulate signals on Windows.

    If Python continues to use emulated condition variables, then the kernel wait in _PyCOND_WAIT_MS can easily be adapted to include the SIGINT event. However, isn't it planned at some point to remove the emulated condition-variable implementation in favor of native condition variables? If so and PyCOND_WAIT and PyCOND_TIMEDWAIT end up calling SleepConditionVariableSRW, there's no obvious way to interrupt this to support Ctrl+C and Ctrl+Break (given a custom SIGBREAK handler) in the main thread.

    In particular, in Windows 8+, SleepConditionVariableSRW begins by spinning in user mode for a fixed number of cycles. Then it calls NtWaitForAlertByThreadId to block until alerted by NtAlertThreadByThreadId, which gets called internally by Wake[All]ConditionVariable. It wouldn't be kosher to call NtAlertThreadByThreadId directly in order to alert the main thread because it's an undocumented system call, plus it's poking into the internal implementation details of SleepConditionVariableSRW and WakeConditionVariable, which could leave the variable in a bad state.

    @eryksun
    Copy link
    Contributor

    eryksun commented Mar 22, 2021

    In bpo-29971 it was suggested to split the PyThread lock API in Windows into an "interruptible lock" API that's based on emulated condition variables and a "fast lock" API that's based on native condition variables and SRW locks. Maybe the only API change that's needed in that regard is to add PyThread_allocate_lock_ex(int interruptible), and otherwise dispatch on the lock type that's set in the PNRMUTEX.

    @eryksun eryksun added 3.10 only security fixes and removed 3.7 (EOL) end of life labels Mar 22, 2021
    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.8 (EOL) end of life 3.9 only security fixes 3.10 only security fixes OS-windows topic-multiprocessing type-bug An unexpected behavior, bug, or error
    Projects
    Status: No status
    Development

    No branches or pull requests

    3 participants