0

シナリオは次のとおりです。

  1. すべてのスレッド間で共有されるプロキシがあります。
  2. このプロキシがブロックされた場合、すべてのスレッドではなく、1 つのスレッドのみが ProxyQueue からプロキシをデキューする必要があります。デキューには、現在インターロックを使用しているため、一度に1つのスレッドしか関数に入ることができません。

                private static volatile string httpProxy = "1.1.1.1";
                private static int usingResource = 0;
                string localHttpProxy;
    
                  try
          {
                                                                                       HttpWebRequest oReqReview =         HttpWebRequest)WebRequest.Create(url);                                                          
    if (IsHttpProxyDequeue)
     {
    oReqReview.Proxy = new WebProxy(httpProxy, 8998);
     localHttpProxy = httpProxy;
    
         }
    HttpWebResponse respReview = (HttpWebResponse)oReqReview.GetResponse();
    DoSomthing();
    }
    catch (Exception ex)
    {
    if (0 == Interlocked.Exchange(ref usingResource, 1))
    {
    
    if (ex.Message == "The remote server returned an error: (403) Forbidden." &&      httpProxy     == localHttpProxy)
    {
                                                                                               IsHttpProxyDequeue =     currentQueueProxy.TryDequeue(out httpProxy);
    
    }
    Interlocked.Exchange(ref usingResource, 0);
    }
    }
    
4

2 に答える 2

2

Interlocked.Exchange はブロックされません。値のスワップを実行し、結果を報告するだけです。の初期値usingResourceが 0 で、3 つのスレッドがInterlocked.Exchangeまったく同時にヒットした場合、1 つのスレッドで Exchange() は 0 を返し、usingResource を 1 に設定し、他の 2 つのスレッドでは Exchange() は 1 を返します。スレッド 2 と 3 if ブロックに続く最初のステートメントですぐに実行を継続します。

スレッド 2 と 3 をスレッド 1 の終了を待ってブロックする場合は、C#lock(object)構文のようなミューテックス ロックのようなものを使用する必要があります。ブロック スレッドをロックします。

Interlocked.Exchangeスレッドをブロックしません。 Interlocked.Exchangeノンブロッキングスレッドコーディネーションを書くときに便利です。Interlocked.Exchangeは、「このスワップから特別な値を取得した場合は、迂回してこの特別な操作を行います。そうでない場合は、待機せずにこの別のことを続けます。」

于 2013-03-19T16:20:03.037 に答える
1

Interlockedその値で同期を提供するため、複数のスレッドが同時にそのポイントに到達した場合、そのうちの 1 つだけが0返されます。1値が「0」に戻されるまで、他のすべての値は元に戻されます。

コードに競合状態があり、おそらくそれが問題の原因です。次の一連のイベントを検討してください。

Thread A sees that `IsProxyDequeue` is `false`
Thread A calls `Interlocked.Exchange` and gets a value of '0'
Thread A logs the error
Thread B sees that `IsProxyDequeue` is `false`
Thread A dequeues the proxy and sets `usingResource` back to `0`
Thread B calls `Interlocked.Exchange` and gets a value of `0`

この時点で、スレッド B もプロキシをデキューしようとしています。

同期を提供する別の方法を考え出す必要があります。次のようなものが必要になると思います。

object lockObj = new object();
lock (lockObj)
{
    if (!IsProxyDequeue)
    {
        // get the proxy
        IsProxyDequeue = true;
    }
    oReqReview.Proxy = new   WebProxy(httpProxy, 8989);
}

競合状態を回避したいが、他のスレッドをブロックしたくない場合Monitor.TryEnterは、lock.

于 2013-03-19T16:25:30.737 に答える