75447


### 環境

[code]

    $ python --version
    Python 3.8.6
    
    $ uname -a
    Linux example 4.18.0-16-generic #17~18.04.1-Ubuntu SMP Tue Feb 12 13:35:51 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
    
    $ cat /proc/cpuinfo
    processor   : 0
    vendor_id   : GenuineIntel
    cpu family  : 6
    model       : 158
    model name  : Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz
    stepping    : 10
    cpu MHz     : 2904.002
    cache size  : 12288 KB
    ...
    
    processor   : 1
    vendor_id   : GenuineIntel
    cpu family  : 6
    model       : 158
    model name  : Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz
    stepping    : 10
    cpu MHz     : 2904.002
    cache size  : 12288 KB
    
    
[/code]

# 背景

[Effective Python 第2版](https://www.oreilly.co.jp/books/9784873119175/)
の項目54「スレッドにおけるデータ競合を防ぐためにLockを使う」を読んで、スレッドについて勉強しています。

# 起こったこと

Lockを使って`LockingCounter`クラスのカウンタが正しいことを確認しようとしました。

以下は`main.py`の中身です。  
<https://github.com/bslatkin/effectivepython/blob/master/example_code/item_54.py#L117...L144>
を参考にしました。

[code]

    from threading import Thread, Lock
    
    def worker(sensor_index, how_many, counter):
        for _ in range(how_many):
            counter.increment(1)
    
    class LockingCounter:
        def __init__(self) -> None:
            self.lock = Lock()
            self.count = 0
        
        def increment(self, offset):
            with self.lock:
                self.count += offset
    
    how_many = 10 ** 5
    counter = LockingCounter()
    threads = []
    for i in range(5):
        thread = Thread(target=worker, args=(i,how_many,counter))
        threads.append(thread)
        thread.start()
    
    for trhead in threads:
        thread.join()
    
    expected = how_many * 5
    found =counter.count
    print(f"Counter should be {expected}, got {found}")
    
    
[/code]

実行したところ、カウンタの値は期待通り`500000`でした。

[code]

    $ python main.py
    Counter should be 500000, got 500000
    
    
[/code]

しかし、何回か実行すると、カウンタの値は`500000`未満になりました。

[code]

    $ for i in {1..10} ; do   python q1.py; done
    ounter should be 500000, got 500000
    Counter should be 500000, got 500000
    Counter should be 500000, got 493650
    Counter should be 500000, got 487159
    Counter should be 500000, got 444995
    Counter should be 500000, got 458824
    Counter should be 500000, got 459648
    Counter should be 500000, got 479945
    Counter should be 500000, got 500000
    Counter should be 500000, got 461983
    
[/code]

# 質問

Lockを使っているのにも関わらず、なぜカウンタの値が`500000`未満になるのでしょうか？


CC BY-SA 4.0
2021-04-22T07:54:19.057
75446
2021-04-22T08:13:23.600
19524
question
python
スレッド演算で相互排他ロックしているつもりですが、ロックできない場合があります。なぜでしょうか？


> for trhead in threads:

このスペルミスのせいでバリア同期が取れてなくて終わってないスレッドがあるだけでは？


CC BY-SA 4.0
2021-04-22T08:13:23.600
75447
2021-04-22T08:13:23.600
75446
answer