线程之间是否共享一个方法的局部变量?

时间:2011-05-28 12:53:07

标签: c# multithreading synchronization

我有这样一个类的实例:

public class One
{
    Semaphore S = null;
    public One(Semaphore S)
    {
        this.S = S;
    }
    public void Run(int ID)
    {
        S.WaitOne();
        Console.WriteLine("Thread [" + ID + "] Entered");
        Random R = new Random();
        Thread.Sleep(R.Next(100, 1000));
        Console.WriteLine("Thread [" + ID + "] Exited");
        S.Release();
    }
}

在我的程序中,我实例化了几个新线程。每个线程在上面的类中运行“Run()”方法。

Semaphore S = new Semaphore(5, 5);
One O = new One(S);
for (int j = 0; j < 10; j++)
{
     Thread T = new Thread(delegate() { O.Run(j); });
     T.Start();
}

我希望看到一个从0到9的数字列表,但是按照非排序的顺序。但是我的结果显示“Run()”方法中的“ID”变量作为局部变量在所有线程之间共享。

 ![Output][1]

我想知道我是否有一个类的实例,并且许多线程从该实例运行一个方法,所以在所有线程之间共享该方法的局部变量?或者每个线程都有自己的本地副本?我应该为该类中的每个线程创建一个新实例吗?

4 个答案:

答案 0 :(得分:6)

不,线程之间不共享局部变量。而你的参数ID在这方面是一个局部变量。它不是共享的。

您看到的是由称为捕获的循环变量的标准问题引起的。使用额外的变量解决它很简单:

for (int j = 0; j < 10; j++)
{
     int copy = j;
     Thread T = new Thread(delegate() { O.Run(copy); });
     T.Start();
}

我希望这表明问题出在哪里:j变量由您的匿名方法捕获,实际上这意味着它由O.Run()的所有调用站点共享(通过引用) 。

答案 1 :(得分:1)

不,线程之间不共享本地人。如果您正在调试线程,请确保打开线程窗口,以便在要查看变量时可以在线程之间切换。否则,如果手表卡在一个螺纹上,可能会产生误导性结果。

我在你的程序的一次运行中得到以下输出,但由于它的性质,你每次都可以得到不同的结果。

Thread [1] Entered
Thread [2] Entered
Thread [4] Entered
Thread [4] Entered
Thread [5] Entered
Thread [2] Exited
Thread [1] Exited
Thread [10] Entered
Thread [6] Entered
Thread [6] Exited
Thread [10] Exited
Thread [9] Entered
Thread [8] Entered
Thread [4] Exited
Thread [5] Exited
Thread [8] Entered
Thread [4] Exited
Thread [8] Exited
Thread [9] Exited
Thread [8] Exited

答案 2 :(得分:1)

试试这个:

static void Main(string[] args)
{
    Semaphore S = new Semaphore(5, 5);
    One O = new One(S);
    for (int j = 0; j < 10; j++)
    {
        Thread T = new Thread(new ParameterizedThreadStart(O.Run));
        T.Start(j);
    }
}

public class One
{
    Semaphore S = null;
    public One(Semaphore S)
    {
        this.S = S;
    }
    public void Run(object ID)
    {
        // int id = (int) ID;  // when you need an int
        S.WaitOne();
        Console.WriteLine("Thread [" + ID + "] Entered");
        Random R = new Random();
        Thread.Sleep(R.Next(100, 1000));
        Console.WriteLine("Thread [" + ID + "] Exited");
        S.Release();
    }
}

答案 3 :(得分:0)

不,线程之间不共享局部变量和方法参数。您所看到的是因为变量j在您正在创建的匿名代理之间共享。因此,在您的情况下,有一个全局j,并且每个线程的Run()获取变量在调用方法时具有的值,这可能是在j为下一个增加for (int j = 0; j < 10; j++) { int tmp = j; Thread T = new Thread(delegate() { O.Run(tmp); }); T.Start(); } 之后迭代。

您可以通过创建一个新变量来解决这个问题,该变量对每次迭代都是“本地的”:

{{1}}