1

クラス ProxyManager のグローバル インスタンスである変数 $proxyManager があります。$proxyManager = ProxyManager.new

このクラスには関数 getProxy があり、複数のスレッドによって何度も呼び出されます。この関数内で、配列から項目をポップしています (これがスレッド セーフであると仮定しましょう)。次に、その識別子を現在の時刻に設定し、アクティブ フラグを設定して、それを返します。

proxy.identifier が設定された後、同じスレッドで「変更」することは可能ですか? 例として、スレッド 1 が識別子を 1 に設定し、すぐにスレッド 2 が同じ行を実行してそれを 2 に設定するとします。これは、スレッド 1 の識別子が 2 になったことを意味しますか?

class ProxyManager
    def getProxy
        key = "proxy"
        proxy = popFromGlobalArray() #assume this operation is thread-safe/atomic

        proxy.identifier = Time.now.to_i
        proxy.active = 1
        return proxy
    end

end
4

3 に答える 3

3

本質的にスレッドセーフではありませんが、正確に何が行われに依存するかによって異なります。また、実装 (「グリーン スレッド」を使用した Ruby 1.8 MRI と Ruby 2 MRI と JRuby など) は、競合状態が発生した場合にどのように発生するかについて重要な役割を果たします。

多くの場合、競合状態は共有データから生じることに注意してください。変数は重要ではありません (スレッドは、再帰メソッドが変数を再利用するのと同様に、別のスレッドのローカル変数を使用しません) が、変数によって名前が付けられたオブジェクト重要です。(注:proxyローカル変数ですが、ローカル変数でproxy.instanceはありません!)

共有データ/オブジェクトを想定した競合状態:

proxy_A = popFromGlobalArray()
proxy_B = popFromGlobalArray() 
# assume same object was returned so that proxy_A.equal? proxy_B is true
proxy_A.identifier = Time.now.to_i
proxy_A.active = 1
proxy_B.identifier = Time.now.to_i # such that it is different
proxy_B.active = 1

この時点での結果は同じであるため、これはあまりエキサイティングではありませんが、返されたオブジェクト (proxy_A と proxy_Bの両方が参照するオブジェクト) が識別子変数の割り当て (およびスレッド可視性の伝播) ので使用されていると想像してください。 - 壊れたコード。

つまり、上記が展開されていると仮定します。

h = {}
# assume same object was returned so that proxy_A.equal? proxy_B is true
proxy_A.identifier = Time.now.to_i
h[proxy_A.identifier] = proxy_A    # i.e. used after return
proxy_B.identifier = Time.now.to_i # such that it is different
h[proxy_B.identifier] = proxy_B    # i.e. used after return
# now there may be an orphaned key/value.  

もちろん、が異なるpopFromGlobalArrayオブジェクトを返すことが保証されている場合、上記は当てはまりませんが、別の問題あります。時間の精度に依存する競合状態です。

proxy_A = popFromGlobalArray()
proxy_B = popFromGlobalArray()
# assume Time.now.to_i returns x for both threads
proxy_A.identifier = x
proxy_B.identifier = x
# and a lost proxy ..
h = {}
h[proxy_A.identifier] = proxy_A
h[proxy_B.identifier] = proxy_B

この話の教訓: 運に頼るな。上記を簡略化して、スレッド間でデータを即座に可視化する際に発生する可能性のある競合状態を示しています。ただし、スレッド間のデータの可視性 (つまり、メモリ フェンスの欠如) により、この問題は最初に見えるよりもはるかに悪化します。

于 2013-03-29T23:00:22.233 に答える
2

popFromGlobalArray () がマルチスレッド環境で正しく機能し、同じオブジェクトを複数回返さないことが保証され、プロキシ クラスの実装がインスタンス間で状態を共有しない場合、関数の残りの部分は問題ありません。異なるスレッドで同じデータを操作していないため、競合することはありません。

変数自体について心配している場合でも、心配する必要はありません。ローカルはメソッド呼び出しごとに定義され、異なるスレッドがメソッドの異なる呼び出しを実行します。彼らは地元の人を共有しません。

明らかに、詳細によってこれが真実でなくなる可能性がありますが、これは一般的にどのように機能するかです.

于 2013-03-30T00:06:32.353 に答える
1

ローカル変数はスレッドごとに定義され、スレッドセーフです。

配列が実際にアトミックである場合、スレッドがこの関数に入るたびにプロキシ変数が異なる項目であることが保証され、他のスレッドが識別子を上書きすることはできません。

于 2013-03-29T22:59:46.153 に答える