0

以下がスレッドセーフかどうか、そうでない場合はどうすればよいか教えてください。

注:これはほんの小さなサンプルであり、実行されるかどうかはわかりません。

TIMER = True
time_lock = threading.Lock()
def timing():
    while TIMER:
        # some logic will be here for now print time
        print time.time()

timer = threading.Thread(target=timing)
timer2 = threading.Thread(target=timing)
timer.start()
timer2.start()

while True:
    time_lock.aquire()
    if doSomeStuff():
        TIMER = True
    if otherThings():
        break
    time_lock.aquire()
    TIMER = False
    time_lock.release()

time_lock.aquire()
TIMER = False
time_lock.release()
4

2 に答える 2

2

使用している実装と、何をしているかによって少し異なります。

まず、 Python の事実上の標準実装 ("cpython") では、Python インタープリターの一部の内部がスレッドセーフではないため、一度に実行できるスレッドは 1 つだけです。これは、Global Interpreter Lock (別名「GIL」) によって制御されます。したがって、cpython では、追加のロックはまったく必要ありません。GIL は、一度に 1 つのスレッドのみが Python コードを実行し、変数を変更する可能性があることを確認します。これは実装の機能であり、言語の機能ではありません。

第 2 に、単純な変数に書き込みを行うスレッドが 1 つだけで、他のスレッドがそれを読み取るだけの場合は、明らかな理由から、ロックも必要ありません。ただし、これが事実であることを確認するのはプログラマーとしてのあなた次第であり、間違いを犯しやすいです。

単純な変数への代入でさえ、ロックを必要としない場合があります。Python では、変数は、何かを入れるボックスというよりも、オブジェクトを参照するために使用されるラベルのようなものです。そのため、単純な代入は (途中で中断できないという意味で) アトミックです。生成された python バイトコード:

In [1]: import dis

In [2]: x = 7

In [3]: def setx():
    global x
    x = 12
   ...:     

In [4]: dis.dis(setx)
  3           0 LOAD_CONST               1 (12)
              3 STORE_GLOBAL             0 (x)
              6 LOAD_CONST               0 (None)
              9 RETURN_VALUE        

x を変更する唯一のコードは、単一のSTORE_GLOBALオペコードです。したがって、変数は変更されているか、変更されていません。間に矛盾した状態はありません。

しかし、たとえば変数の特定の値をテストし、そのテストがまだ true である間にアクションを実行したい場合は、ロックが必要です。テストした直後に別のスレッドが変数を変更した可能性があるためです。

リストへの追加や変数の交換などはアトミックではありません。しかし、cpython では、これらは GIL によって保護されます。他の実装では、可能性のある不整合から保護するために、そのような操作をロックする必要があります。

于 2012-10-24T18:08:41.307 に答える
1

私があなたのことを正しく理解していれば、停止するタイミングをスレッドに知らせる必要があります。これは、1 つのスレッドだけが共有変数に 1 回だけ書き込む状況であるため、ロックは必要ありません。

アトミックに読み取ることができない共有データ構造を同時に変更する場合は、ロックが必要です。

于 2012-10-24T13:23:24.450 に答える