

WindowsOS + Python(3.7.5)環境でシグナルを受け取りたいのですが、受け取らずにプロセスが落ちてしまいます。  
原因、対処方法についてご存知の方がいらっしゃいましたら、ご教授いただけないでしょうか。

_receiver_test.py_

[code]

    import time
    import signal
    
    def received(signum, stack):
        print("RECEIVED!")
    
    signal.signal(signal.SIGINT, received)
    print("Start sleep...")
    while True:
        time.sleep(1)
    
[/code]

_killer_test.py_

[code]

    import os
    import signal
    
    pid = XXX  # receiver_test.pyのプロセスIDを指定
    os.kill(pid, signal.SIGINT)
    
[/code]

コマンドプロンプトを2つ立ち上げて、それぞれreceive_test.pyとkiller_test.pyを実行しました。

実行結果：  
↓ killer_test.py実行後、RECEIVED!が表示されずにプロセスが終了する

[code]

    > python receive_test.py
    Start sleep...
    
    >
    
[/code]


CC BY-SA 4.0
2020-01-22T11:49:37.913
62459
2020-01-23T04:11:28.700
2020-01-22T12:54:50.413
19110
37551
question
python windows
Windows環境でPythonのシグナルを受け取れない


[os.kill](https://docs.python.org/ja/3.7/library/os.html#os.kill)には

> Windows: signal.CTRL_C_EVENT と signal.CTRL_BREAK_EVENT
> は、同じコンソールウィンドウを共有しているコンソールプロセス ( 例 : 子プロセス ) にだけ送ることができる特別なシグナルです。その他の値を sig
> に与えると、そのプロセスが無条件に TerminateProcess API によって kill され、終了コードが sig に設定されます。

と説明されているので、signal.CTRL_C_EVENT と signal.CTRL_BREAK_EVENT
以外は使えず、これらも同じコンソールを共有している必要があります。  
なお、TerminateProcessはkill -9相当で、受け取ったプロセスは一切の処理が行えません。


CC BY-SA 4.0
2020-01-22T12:11:45.430
62460
2020-01-22T12:11:45.430
4236
62459
answer


コメントで紹介した記事を試してみました。Windows10 64bit, Python 3.7.6 です。  
[keyboard 0.13.4](https://pypi.org/project/keyboard/)と[pywin32
227](https://pypi.org/project/pywin32/)の[Module
win32gui](http://timgolden.me.uk/pywin32-docs/win32gui.html)を使っています。

対象ウインドウへフォーカスはこちらの回答を使用  
[Python Window Activation](https://stackoverflow.com/q/2090464/9014308)

キー押下の通知はこちらの質問を使用  
[Python “keyboard” module: Release keys to allow
copy/Ctrl+C](https://stackoverflow.com/q/57297394/9014308)

受信側のスクリプトは何も変更していません。

通知側のスクリプトは以下。CTRL+Cの通知

[code]

    import win32gui
    import re
    import keyboard
    
    class WindowMgr:
        """Encapsulates some calls to the winapi for window management"""
    
        def __init__ (self):
            """Constructor"""
            self._handle = None
    
        def find_window(self, class_name, window_name=None):
            """find a window by its class_name"""
            self._handle = win32gui.FindWindow(class_name, window_name)
    
        def _window_enum_callback(self, hwnd, wildcard):
            """Pass to win32gui.EnumWindows() to check all the opened windows"""
            if re.match(wildcard, str(win32gui.GetWindowText(hwnd))) is not None:
                self._handle = hwnd
    
        def find_window_wildcard(self, wildcard):
            """find a window whose title matches the wildcard regex"""
            self._handle = None
            win32gui.EnumWindows(self._window_enum_callback, wildcard)
    
        def set_foreground(self):
            """put the window in the foreground"""
            win32gui.SetForegroundWindow(self._handle)
    
    w = WindowMgr()
    w.find_window_wildcard(".*receiver_test.*") # 検索するウインドウタイトルはスクリプト名のもの
    w.set_foreground()
    
    keyboard.press_and_release('ctrl+c')
    
[/code]

CTRL+BREAKは上記の最後を以下に変更

[code]

    keyboard.press_and_release('ctrl+break')
    
[/code]

結果は以下の様に、`ctrl+c`を通知すると`SIGINT`の処理が行われて`RECEIVED!`の表示で処理が続行され、`ctrl+break`を通知すると`^C`を表示してスクリプトが終了しています。

[![WindowsSignal](https://i.stack.imgur.com/oekFZ.png)](https://i.stack.imgur.com/oekFZ.png)

これが使えるか/使いやすいか、は分かりませんが、こんなことも出来るということで。


CC BY-SA 4.0
2020-01-23T04:11:28.700
62477
2020-01-23T04:11:28.700
26370
62459
answer