Являются ли локальные переменные одного метода общими для потоков? - PullRequest
2 голосов
/ 28 мая 2011

У меня есть экземпляр из класса, подобного этому:

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, но в несортированном порядке. но мой результат показывает, что переменная "ID" в методе "Run ()" как локальная переменная является общей для всех потоков.

 ![Output][1]

Я хочу знать, есть ли у меня один экземпляр класса, и многие ли потоки запускают метод из этого экземпляра, поэтому локальные переменные этого метода совместно используются всеми потоками? или каждый поток имеет свою локальную копию? Должен ли я создать новый экземпляр для каждого потока из этого класса?

Ответы [ 4 ]

6 голосов
/ 28 мая 2011

Нет, локальные переменные не разделяются между потоками. И ваш параметр ID является локальной переменной в этом отношении. Это не общедоступно.

То, что вы видите, вызвано стандартной проблемой, называемой захваченный цикл var . Это просто решить с помощью дополнительной переменной:

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

И я надеюсь, что это показывает, в чем проблема: переменная j перехватывается вашим анонимным методом, по сути это означает, что она используется (по ссылке) всеми call-сайтами O.Run().

1 голос
/ 28 мая 2011

попробуйте это:

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();
    }
}
1 голос
/ 28 мая 2011

Нет, местные жители не делятся между потоками.Если вы отлаживаете потоки, обязательно откройте окно потоков, чтобы вы могли переключаться между потоками, если хотите посмотреть переменную.В противном случае вы можете получить вводящие в заблуждение результаты, если часы застряли в одном потоке.

Я получаю следующий вывод при одном запуске вашей программы, хотя по своей природе вы можете каждый раз получать разные результаты.

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
0 голосов
/ 28 мая 2011

Нет, ни локальные переменные, ни параметры метода не разделяются между потоками.То, что вы видите, это то, что переменная j совместно используется созданными вами анонимными делегатами.Таким образом, в вашем случае есть один глобальный j, и каждый поток Run() получает значение, которое имеет переменная при вызове метода, что может быть после того, как j увеличится для следующей итерации.1006 * Это можно исправить, создав новую переменную, которая является «локальной» для каждой итерации:

for (int j = 0; j < 10; j++)
{
     int tmp = j;
     Thread T = new Thread(delegate() { O.Run(tmp); });
     T.Start();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...