【问题标题】:Are the local variables of one method shared between threads?一种方法的局部变量是否在线程之间共享?
【发布时间】:2011-05-28 12:53:07
【问题描述】:

我有这样一个类的实例:

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]

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

【问题讨论】:

  • 我认为共享的不是 ID 变量,而是循环中的 j 。我认为它是通过引用传递给代表的,所以他们都看到同一个 ..

标签: c# multithreading synchronization


【解决方案1】:

不,局部变量不在线程之间共享。在这方面,您的参数 ID 是本地变量。它不共享。

您看到的是由一个称为捕获的循环变量 的标准问题引起的。用一个额外的变量很容易解决:

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

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

【讨论】:

    【解决方案2】:

    不,线程之间不共享局部变量。如果您正在调试线程,请务必打开线程窗口,以便在要查看变量时在线程之间切换。否则,如果手表卡在一个线程上,您可能会得到误导性的结果。

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

    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
    

    【讨论】:

      【解决方案3】:

      试试这个:

      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();
          }
      }
      

      【讨论】:

        【解决方案4】:

        不,局部变量和方法参数都不在线程之间共享。您所看到的是因为变量 j 在您正在创建的匿名委托之间共享。因此,在您的情况下,有一个全局 j 并且每个线程的 Run() 在调用该方法时获取变量具有的值,这可能是在 j 为下一次迭代递增之后。

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

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

        【讨论】:

          猜你喜欢
          • 2014-04-27
          • 2011-06-23
          • 2021-08-14
          • 2011-11-09
          • 2021-12-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多