LoginSignup
5
5

More than 3 years have passed since last update.

Ctrl+C で止まらないpythonプログラム

Last updated at Posted at 2019-12-16

この記事は 鈴鹿高専 Advent Calendar 2019 にも登録しました。

経緯

  • #procon30の出場作品での出来事
  • 組み込み系のコードをpython 2.7で書いていた
  • 自分がセンサ類のモジュール3つを担当した
  • モジュール単体では、Ctrl+Cで正常終了した(定期的なセンシングのため、デーモンプロセスと考えておk)
  • 全体制御を👨‍💻に任せていた
  • 統合テストではCtrl+Cでも終了しない
  • 👨‍💻は問題を放置し、Ctrl+Zkill -9で強引にプロセスを終了させていた
  • 本選後に原因を発見し、今でも忘れられないので記事にする

問題のプログラム

👨‍💻は参照渡し時にイミュータブル(変更不可)な変数は変更されないことを知らなかったらしい。(ドキュメント

main.py
import os
import threading
import time
import foo_1   # foo_1.py

std_lock = threading.Lock()   # 標準入力時の排他制御

if __name__ == "__main__":
    foo_1_thread = threading.Thread(target=foo1.foo_1,args=(std_lock,))
    foo_1_thread.start()
    while True:
        try:
            with std_lock:
                print("thread name:{0}, ident:{1}".format("main", threading._get_ident()))
            time.sleep(1)
        except KeyboardInterrupt:
            break
foo_1.py
import time
import threading

terminate = False

def foo_1(std_lock):
    while False == terminate:   # while == True じゃ止まんないから変えといたYo!^^ by👨‍💻
        with std_lock:
            print("thread name:{0}, ident:{1}, terminate:{2}".format("foo_1", threading._get_ident(),terminate))
        time.sleep(1)
実行結果
$ python main.py
thread name:foo_1, ident:140618926196480, terminate:False
thread name:main, ident:140618956166976
thread name:main, ident:140618956166976
thread name:foo_1, ident:140618926196480, terminate:False
thread name:main, ident:140618956166976
thread name:foo_1, ident:140618926196480, terminate:False
^C
thread name:foo_1, ident:140618926196480, terminate:False
thread name:foo_1, ident:140618926196480, terminate:False
thread name:foo_1, ident:140618926196480, terminate:False
^Z
[1]  + 15221 suspended  python main.py

止め方

リスト型はミュータブル(変更可能)なので、terminate = Falseterminate = [False]にして、terminate[0]をいじれば止まる。

が、そんな止め方はイケてないので、threading.Threadを継承し、スレッドをデーモンに設定して止まるようにした。

main.py変更箇所
- foo_1_thread = threading.Thread(target=foo1.foo_1,args=(std_lock,))
+ foo1_thread = foo_1.foo_1(std_lock)
foo_1.py
import time
import threading

class foo_1(threading.Thread):
    def __init__(self,std_lock):
        super(foo_1, self).__init__()
        self.daemon = True
        self.std_lock = std_lock

    def run(self):
        while True:
            with self.std_lock:
                print("thread name:{0}, ident:{1}".format("foo_1", threading._get_ident()))
            time.sleep(1)
実行結果
$ python qiita_test.py
thread name:foo_1, ident:140555638449920
thread name:main , ident:140555668420416
thread name:foo_1, ident:140555638449920
thread name:main , ident:140555668420416
thread name:foo_1, ident:140555638449920
thread name:main , ident:140555668420416
^C

ドキュメントは英語でもちゃんと読みましょう

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5