

multiprocessing.Processでtarget関数(引数`target`として渡す関数)のなかでSIGTERMをハンドルしたいのですがうまくいきません  
どうすればいいのでしょうか?

GUIを使ったプログラムでStartボタンを押すと別プロセスで`test_main`関数が動きます  
Stopボタンを押すとStartボタンを押したときに起動したプロセスにSIGTERMが送られます  
しかし、test_main内ではWebdriverが動いており、このWebdriverを片付けてから(driver.quit()してから)プロセスを終了させたいです。

そこでtest_main内でsignal.signalを設定してSIGTERMを受け取ったらwebdriverを片付けた後でプロセスを終了させたいのですがStopボタンを押してSIGTERMを送ってもうまくいきません

[code]

    
    import tkinter as tk
    from multiprocessing import Process
    from tkinter import messagebox
    import sys
    import signal
    import time
    import os
    from selenium.webdriver.support.wait import WebDriverWait
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    from selenium.webdriver.chrome.options import Options
    from selenium.webdriver.support import expected_conditions as EC
    
    
    def create_driver():
        options = Options()
        if sys.platform == "darwin":
            options.binary_location = '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary'
        #options.add_experimental_option("detach", True)
        if sys.platform == "win32":
            options.binary_location = "C:\\(user_home)\\AppData\\Local\\Google\\Chrome SxS\\Application\\chrome.exe" #location of chrome canary for windows
        options.add_argument('--headless')
        #options.add_argument('--disable-gpu')
        options.add_argument('--reduce-security-for-testing')
        options.add_argument('--allow-insecure-localhost')
        if sys.platform == "win32":
            chromedriver_path = r".\chromedriver"
        else:
            chromedriver_path = "./chromedriver"
    
        driver = webdriver.Chrome(chromedriver_path, chrome_options=options)
        return driver
    
    
    
    class GUI(tk.Frame):
        def __init__(self, master=None):
            super().__init__(master)
            self.cur_process = None
            self.pack()
            self.create_widget()
    
        def create_widget(self):
            self.start = tk.Button(self, width=5, padx=10, pady=3)
            self.start["text"] = "Start"
            self.start["command"] = self.start_event
            self.start.grid(row=2, column=2, columnspan=2, padx=4, pady=10)
            self.quit = tk.Button(self, width=5, padx=10, pady=3)
            self.quit["text"] = "Stop"
            self.quit["command"] = self.stop_event
            self.quit.grid(row=3, column=2, columnspan=2, padx=4, pady=10)
    
        def start_event(self):
            if self.cur_process is None:
                self.cur_process = Process(target=test_main) #target function
                self.cur_process.start()
    
        def stop_event(self):
            if self.cur_process != None:
                os.kill(self.cur_process.pid, signal.SIGTERM)
    #            self.driver.quit()
                self.cur_process = None
    
    
    def test_main(): #target function
        # set signal handler to SIGTERM
        def k():
            print("set new signal handler")
            try:
                driver.quit()
                # then terminate process
            except NameError:# driver is not defined
                pass # do nothing
            sys.exit() # terminate process
        signal.signal(signal.SIGTERM, k)
        # do something with driver
        driver = create_driver()
    def gui():
        root = tk.Tk()
        root.geometry("400x300")
        g = GUI(master=root)
        g.mainloop()
    
    
    if __name__ == "__main__":
        gui()
    
    
    
[/code]


CC BY-SA 3.0
2017-11-27T14:16:52.107
39887
2020-09-23T04:06:00.580
2017-11-27T15:19:40.460
5246
5246
question
windows python3 selenium-webdriver
multiprocessing.Processのtarget内でsignalをhandleできない


もしかしたら見当違いの回答になってしまうかもしれませんが、自分でSIGTERMを捕まえてワーカープロセスの掃除をするよりは、ワーカープロセスを
daemonモードで動かしてしまうのはどうでしょうか。

<http://ja.pymotw.com/2/multiprocessing/basics.html#id3>

daemonモードで動かすとそのワーカープロセスはメインのプログラムが終了するとその直前に、自動的に終了してくれるようです。

追記: 質問文を良くみたら「ストップボタン=プログラム終了」ではないので、この回答は妥当ではないですね。すいません。


CC BY-SA 3.0
2017-11-27T15:12:41.740
39891
2017-11-27T15:12:41.740
2168
39887
answer


Windows限定ですが、/fの強制終了と/tの子プロセス含むのオプションを付けて、taskkillコマンドを実行するのが良いかもしれません。  
[release Selenium chromedriver.exe from
memory](https://stackoverflow.com/questions/21320837/release-selenium-
chromedriver-exe-from-memory)  
[Is it possible to kill a process on Windows from within
Python?](https://stackoverflow.com/questions/6278847/is-it-possible-to-kill-a-
process-on-windows-from-within-python)

あるいは、アプリで作った自分の子プロセスとseleniumで作ったWebDriverの子プロセスの両方を別々に終了させる必要があるのかもしれません。

なお、必要ならばrunasで管理者権限にて実行することもできるはずです。  
[Set administrator privileges to subprocess.check_call() in
Python](https://stackoverflow.com/questions/20505893/set-administrator-
privileges-to-subprocess-check-call-in-python)  
[Request UAC elevation from within a Python
script?](https://stackoverflow.com/questions/130763/request-uac-elevation-
from-within-a-python-script)  
[Run .exe file via Python as
Administrator](https://superuser.com/questions/615654/run-exe-file-via-python-
as-administrator)


CC BY-SA 3.0
2017-12-15T00:57:38.563
40289
2017-12-15T01:48:52.600
2017-12-15T01:48:52.600
26370
26370
39887
answer