2013-08-23 35 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表达式使用。