3

複数のスレッドが同じ関数にアクセスする場合、ロックメカニズムを明示的に実装する必要がありますか。

スレッドを使用したプログラムがあります。と の 2 つのスレッドがt1ありt2ます。t1is foradd1()t2is for subtract1().両方のスレッドが同時に同じ関数にアクセスするmyfunction(caller,num)

1. 変数を使用して、特定のプログラムで単純なロック メカニズムを定義しましたfunctionLock。これは信頼できるものですか、それとも変更する必要がありますか。

import time, threading

functionLock = '' # blank means lock is open        

def myfunction(caller,num):
    global functionLock
    while functionLock!='': # check and wait until the lock is open
        print "locked by "+ str(functionLock)
        time.sleep(1)

    functionLock = caller # apply lock

    total=0
    if caller=='add1':
        total+=num
        print"1. addition finish with Total:"+str(total)
        time.sleep(2)
        total+=num
        print"2. addition finish with Total:"+str(total)
        time.sleep(2)
        total+=num
        print"3. addition finish with Total:"+str(total)

    else:
        time.sleep(1)
        total-=num
        print"\nSubtraction finish with Total:"+str(total)

    print '\n For '+caller+'() Total: '+str(total)

    functionLock='' # release the lock


def add1(arg1, arg2):

    print '\n START add'
    myfunction('add1',10)
    print '\n END add'        


def subtract1():

  print '\n START Sub'  
  myfunction('sub1',100)   
  print '\n END Sub'


def main():

    t1 = threading.Thread(target=add1, args=('arg1','arg2'))
    t2 = threading.Thread(target=subtract1)
    t1.start()
    t2.start()


if __name__ == "__main__":
  main()

出力は次のとおりです。

START add
START Sub
1. addition finish with Total:10
locked by add1
locked by add1
2. addition finish with Total:20
locked by add1
locked by add1
3. addition finish with Total:30 
locked by add1
 For add1() Total: 30
 END add
Subtraction finish with Total:-100
 For sub1() Total: -100
 END Sub

2. ロックを使わなくても大丈夫ですか?

上記のプログラムで定義されたロック メカニズムを使用しなくても、結果はスレッド t1 と t2 の両方から同じになります。これは、複数のスレッドが同じ関数にアクセスすると、python が自動的にロックを実装するということですか。

functionLock上記のプログラムでロックを使用しない場合のプログラムの出力

START add
START Sub
1. addition finish with Total:10
Subtraction finish with Total:-100
For sub1() Total: -100
END Sub
2. addition finish with Total:20
3. addition finish with Total:30
For add1() Total: 30
END add

ありがとう!

4

4 に答える 4

1

変数の待機で忙しいというこのスレッドに関する他のコメントに加えて、どのような種類のアトミックスワップも使用していないという事実が、同時実行のバグを引き起こす可能性があることを指摘したいと思います。テストの実行によってそれらが発生することはありませんが、異なるタイミングで十分な繰り返しを実行すると、次の一連のイベントが発生する可能性があります。

スレッド#1が実行while functionLock!=''され、が取得されFalseます。次に、スレッド#1が中断され(他の何かが実行されるためにプリエンプトされます)、スレッド#2while functionLock!=''も同じ行を実行し、。を取得しFalseます。この例では、両方のスレッドがクリティカルセクションに入っていますが、これは明らかにあなたが望んでいたものではありません。特に、スレッドが変更される行ではtotal、両方のスレッドが同時にそのセクションに存在する可能性があるため、期待した結果にならない場合があります。次の例を参照してください。

totalです10。簡単にするために、num常に1と仮定します。スレッド#1はtotal+=num、を実行します。これは、(i)の値のロードtotal、(ii)値の追加、numおよび(iii)結果の。への格納の3つの操作で構成されtotalます。(i)の後、Thread#1がプリエンプトされ、Thread#2が実行されるtotal-=num場合、totalはに設定され9ます。その後、スレッド#1が再開されます。ただし、すでにロードされているtotal = 10ため、1を加算11して変数に格納しtotalます。これにより、スレッド#2によるデクリメント操作がノーオペレーションで効果的に変換されました。

@ ron-kleinによってリンクされているウィキペディアの記事では、コードがxchg操作を使用していることに注意してください。この操作は、レジスターを変数とアトミックに交換します。これは、ロックの修正に不可欠です。結論として、並行性のバグをデバッグするのが非常に難しい場合は、アトミック操作の代わりに独自のロックを実装しないでください。

[編集]実際にはコード内のローカル変数であることに気付いたtotalので、これは決して起こり得ません。ただし、「複数のスレッドが同じ関数にアクセスすると、Pythonが自動的にロックを実装することを意味しますか?」と断言しているため、これがコードが完全に機能している原因であることに気付いていないと思います。これは正しくありません。global totalの先頭に追加してmyfunction、スレッドを数回実行してみてください。出力にエラーが表示されるはずです。[/編集]

于 2013-03-14T17:44:22.813 に答える
1
  1. コードでは、独自のspin-lockを実装します。これは可能ですが、パフォーマンスの問題につながる可能性があるため、Python では推奨されていないと思います。

  2. よく知られた検索エンジン (で始まるG) を使用して、「python lock」について問い合わせました。最初の結果の 1 つは次のとおりです: Thread Synchronization Mechanisms in Python。始めるには良い記事のようです。

  3. コード自体について: 共有リソースで実行される操作がアトミックでない場合は常にロックする必要があります。現在、コードにはそのようなリソースがないようです。

于 2013-03-14T06:34:59.680 に答える
1

私は Python についてあまり知りませんが、これは他の言語と同じだと思います。

関数の外部で宣言され、スレッド間で共有できる変数が含まれていない限り、ロックは必要ありません。そして、これはあなたの機能には当てはまらないようです。

ただし、コンソールへの出力は文字化けする可能性があります。

于 2013-03-14T06:19:44.540 に答える
1

書いているコードがクリティカル セクション コードであると思われる場合、つまり、コード スニペットがスレッド間の共有状態を変更している場合は、ロックする必要があります。そうでない場合は、ロックについて心配する必要はありません。

メソッドをロックするかどうかは設計上の選択です。理想的には、スレッドによる共有状態アクセスの近くでロックする必要があります。

于 2013-03-14T06:20:31.753 に答える