2013-08-23 69 views
3

我有以下C#代碼片段,其中我模擬了我的問題。在此程序中,我有調用ReadRooms方法的Service函數。 現在我正在調用不同線程上的服務方法。我期待ServiceCall和ReadRooms方法都會同時觸發,但我得到的結果不正確。多個線程在C調用相同的方法#

enter image description here

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     public static void ReadRooms(int i) 
     { 
      Console.WriteLine("Reading Room::" + i); 
      Thread.Sleep(2000); 
     } 
     public static void CallService(int i) 
     { 
      Console.WriteLine("ServiceCall::" + i); 
      ReadRooms(i); 

     } 
     static void Main(string[] args) 
     { 
      Thread[] ts = new Thread[4]; 
      for (int i = 0; i < 4; i++) 
      { 
       ts[i] = new Thread(() => 
        { 
         int temp = i; 
         CallService(temp); 


        }); 
       ts[i].Start(); 
      } 
      for (int i = 0; i < 4; i++) 
      { 
       ts[i].Join(); 
      } 
      Console.WriteLine("done"); 
      Console.Read(); 

     } 
    } 
} 
+0

嘗試爲您調用的方法添加'[MethodImpl(MethodImplOptions.Synchronized)]''。類似於java中的'synchronized'關鍵字 – sircapsalot

+0

@sircapsalot:我試過了,但仍然出現錯誤結果 –

回答

7

你還在「捕捉循環變量」 。您正在創建temp,但當i已被捕獲時,太晚了。

試試這個:

for (int i = 0; i < 4; i++) 
{ 
    int temp = i;    // outside the lambda 
    ts[i] = new Thread(() => 
    { 
     //int temp = i;  // not here 
     CallService(temp); 
    }); 
    ts[i].Start(); 
} 
2

你的線程動作關閉在可變i,而不是它的當前值。因此,在讀取i的線程和for循環中的增量之間存在競爭。你可以把它作爲一個參數,而不是:

ts[i] = new Thread(index => 
{ 
    CallService((int)index); 
}); 
ts[i].Start(i); 

或者你也可以的temp副本移到循環,而不是線程的動作裏面:

for (int i = 0; i < 4; i++) 
{ 
    int temp = i; 
    ts[i] = new Thread(() => 
    { 
     CallService(temp); 
    }); 
    ts[i].Start(); 
} 
+3

沒有比賽'i' –

+0

@HenkHolterman - 如果'i'在線程讀取值之前遞增,則不同的線程可以看到相同的值。那不是一場比賽? – Lee

+1

這不是我們通常所說的比賽,因爲「我」不打算在第一時間分享。這是真實的,但不是核心問題。這不是你可以用'lock'修復的東西。 –

2

你應該把這個線

int temp = i; 

線程創建

for (int i = 0; i < 4; i++) 
{ 
    int temp = i; 
    ts[i] = new Thread(() => CallService(temp)); 
    ts[i].Start(); 
} 

這樣,您將創建我的本地副本,這將是前由lambda表達式使用。