まず、次のコードを確認してください:
_class DemoClass():
def __init__(self):
#### I really want to know if self.Counter is thread-safe.
self.Counter = 0
def Increase(self):
self.Counter = self.Counter + 1
def Decrease(self):
self.Counter = self.Counter - 1
def DoThis(self):
while True:
Do something
if A happens:
self.Increase()
else:
self.Decrease()
time.sleep(randomSecs)
def DoThat(self):
while True:
Do other things
if B happens:
self.Increase()
else:
self.Decrease()
time.sleep(randomSecs)
def ThreadSafeOrNot(self):
InterestingThreadA = threading.Thread(target = self.DoThis, args = ())
InterestingThreadA.start()
InterestingThreadB = threading.Thread(target = self.DoThat, args = ())
InterestingThreadB.start()
_
上記と同じ状況です。 _self.Counter
_に対してスレッドセーフかどうか本当に知りたいのですが、そうでない場合、どのようなオプションがありますか?私はthreading.RLock()
だけを考えて、このリソースをロックすることができます。
ロック、RLock、セマフォ、条件、イベント、およびキューを使用できます。
そしてこの記事は私を助けてくれましたたくさん。
確認してください: Laurent Luceのブログ
インスタンスフィールドself.Counter
の使用は スレッドセーフまたは「アトミック」 です。それを読み取るか、single値を割り当てる-メモリに4バイトが必要な場合でも、半分変更された値を取得することはありません。しかし、操作self.Counter = self.Counter + 1
は、値を読み取ってから書き込むためではありません。別のスレッドが、読み取られてから書き戻される前に、フィールドの値を変更する可能性があります。
したがって、操作全体をロックで保護する必要があります。
メソッド本体は基本的に操作全体なので、デコレータを使用してこれを行うことができます。例については、この回答を参照してください: https://stackoverflow.com/a/490090/34088
いいえ、それはスレッドセーフではありません。2つのスレッドは基本的に同じ変数を同時に変更しています。そして、はい、解決策はthreading
モジュールのロックメカニズムの1つです。
ところで、self.Counter
はインスタンス変数であり、クラス変数ではありません。
_self.Counter
_はインスタンス変数であるため、各スレッドにコピーがあります。
__init__()
の外で変数を宣言すると、それはクラス変数になります。クラスのすべてのインスタンスがそのインスタンスを共有します。