71586


**問題**  
threadingを使用して0から100を足すプログラムを2つ立ててその合計値を監視する関数で200%になるまで監視したいのですが、200%になった途端エラーが出力されます。スレッドを使用するプログラムを作成するのは始めてなのでこのような書き方で合っているのか分からないの詳しい方に見て頂きたいと思い質問させて頂きました。

プログラムが最後まで動作するようにしたいです。

よろしくお願いします。

**コード**

[code]

    import time
    import threading
    import sys
    
    class AddingNumber():
        def __init__(self):
            self.sum = 0
        
        def adding(self):
            for i in range(100):
                time.sleep(.1)
                self.sum += 1
        
        def progress(self):
            while True:
                sys.stdout.write('{percent}%\r'.format(percent=self.sum))
            
    calculation = AddingNumber()
    
    t2 = threading.Thread(target=calculation.progress)
    t2.setDaemon(True) 
    t2.start()
    
    for i in range(2):
        t = threading.Thread(target=calculation.adding)
        t.start()
        t.join()
    
    print(calculation.sum)
    
[/code]

**エラー内容**

[code]

    Fatal Python error: could not acquire lock for <_io.BufferedWriter name='<stdout>'> at interpreter shutdown, possibly due to daemon threads
    
    Current thread 0x00007fffb20a8380 (most recent call first):
    Abort trap: 6
    
[/code]


CC BY-SA 4.0
2020-10-29T06:20:14.793
71582
2020-10-29T08:24:40.030
2020-10-29T07:10:41.067
22565
22565
question
python python3 非同期
pythonのスレッドを使って計算途中の値を監視するプログラムを書いたのですが、while文を終了するには


合計値を`stdout`に出力する処理が、`while
True:`で無限ループになっていてメインスレッドの終了監視処理(そんなものが可能か？は不明ですが)も無いので、`daemon`設定されていたとしても、メインスレッドが終了して`stdout`が`close`された後、`daemon`スレッドが終了させられる前にも`sys.stdout.write()`処理が走ってしまうのだと思われます。

明示的に監視スレッドを停止させる機能を持たせて、プログラム終了前にそれを呼び出す必要があるでしょう。  
以下のような変更が考えられます。####でコメントした所が変更・追加点です。

[code]

    import time
    import threading
    import sys
    
    class AddingNumber():
        def __init__(self):
            self.sum = 0
            self.Loop = True  #### ループ制御用のフラグを設ける
        
        def adding(self):
            for i in range(100):
                time.sleep(.1)
                self.sum += 1
        
        def terminate(self):      #### ループ停止用メソッド追加
            self.Loop = False
        
        def progress(self):
            while self.Loop: #### 無限ループでは無く制御用フラグを見て継続・終了する
                sys.stdout.write('{percent}%\r'.format(percent=self.sum))
    
    calculation = AddingNumber()
    
    t2 = threading.Thread(target=calculation.progress)
    t2.setDaemon(True) 
    t2.start()
    
    for i in range(2):
        t = threading.Thread(target=calculation.adding)
        t.start()
        t.join()
    
    calculation.terminate() #### 監視スレッド停止指示
    t2.join()               #### 監視スレッド終了待ち
    
    print(calculation.sum)
    
[/code]

* * *

ちなみに細かい仕組みについてはこちらの記事の懸賞ポイントの付いた回答で解説されているようです。  
[Fatal Python error and
`BufferedWriter`](https://stackoverflow.com/q/45267439/9014308)

* * *

**コメント対応：**

`def adding(self):`の中の`for i in
range(100):`の`range`の値をパラメータ指定したい場合は、以下の記事が参考になるでしょう。  
[Pythonのスレッドで引数を渡せなくて躓いた話。](https://meiei.hatenablog.com/entry/2019/12/17/213639)

`def adding(self):`の部分を以下のようにして：

[code]

    def adding(self, count):
        for i in range(count):
            time.sleep(.1)
            self.sum += 1
    
[/code]

スレッド生成部分を以下のようにすれば良いでしょう(例えば150を指定)：

[code]

    t = threading.Thread(target=calculation.adding, args=(150,))
    
[/code]


CC BY-SA 4.0
2020-10-29T07:14:36.307
71586
2020-10-29T07:54:36.220
2020-10-29T07:54:36.220
26370
26370
71582
answer