2013-03-19 70 views
0

下面是這種情況:做一個函數只是一個時間只能有一個線程在TPL

  1. 我有一個是所有的線程之間共享的代理。
  2. 如果這個代理被阻塞,那麼只有一個線程需要從ProxyQueue中取出一個代理,而不是所有的代理。 爲了出隊,我現在使用互鎖,所以一次只能有一個線程可以輸入函數。

      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); 
    } 
    } 
    
+3

你的問題是什麼?什麼不適合你? – dthorpe 2013-03-19 15:53:24

+0

這段代碼不像我描述的那樣工作。只是想知道是否有多個線程聯鎖,他們是否等到聯鎖可用?如果是的話,那麼getproxy函數會重複多次 – MT467 2013-03-19 16:04:55

+1

「如果這個代理被阻塞」是什麼意思? – theMayer 2013-03-21 00:10:42

回答

2

Interlocked.Exchange不會阻塞。它只是執行值的交換並報告結果。如果usingResource的初始值爲0,並且三個線程在同一時間點擊Interlocked.Exchange,則在一個線程上,Exchange()將返回零並將usingResource設置爲1,而在另外兩個線程上,Exchange()將返回1.線程2並且3將立即繼續執行if塊後面的第一條語句。

如果您希望線程2和3阻塞等待線程1完成,那麼您應該使用類似於C#lock(object)語法的互斥鎖。鎖定線程。

Interlocked.Exchange不會阻塞線程。 Interlocked.Exchange在編寫非阻塞線程協調時很有用。 Interlocked.Exchange說:「如果我從這個交換中獲得特殊價值,我會繞道而行,做這個特殊的操作,否則我會繼續做這件事而不用等待。」

+0

很好的解釋!然後互鎖正是我所期待的。我不希望其他線程等待。我在互鎖之前使用了mutext,在我的情況下它沒有用處。 – MT467 2013-03-19 16:38:06

1

Interlocked確實提供了該值的同步,所以如果多個線程同時到達該點,則只有其中一個線程會返回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

+0

這是導致問題的場景之一。我在catch語句中使用getproxy,那麼如何在那裏應用你的邏輯? – MT467 2013-03-19 16:44:24

+0

你將不得不顯示一些代碼。我沒有上下文來解釋「在捕獲聲明」中所指的是什麼。 – 2013-03-19 18:28:33

+0

編輯頂部的代碼 – MT467 2013-03-19 21:15:08