Are the local variables of one method shared between threads?
I have instance from a class like this:
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();
}
}
In my program I instantiate several new threads. Each thread runs the "Run()" method in开发者_JS百科 the above class.
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();
}
I expected to see a list of numbers from 0 to 9 but in non-sorted order. but my result shows that the "ID" variable in "Run()" method as a local variable is shared between all threads.
![Output][1]
I want to know if I have one instance of a class and many threads run a method from that instance, so are the local variables of that method shared between all threads? or each thread has its own local copy? Should I create a new instance for each thread from that class?
No, local variables are not shared between threads. And your paramter ID
is a local var in this respect. It is not shared.
What you see is caused by a standard problem called the captured loop var. It is simple to solve with an extra variable:
for (int j = 0; j < 10; j++)
{
int copy = j;
Thread T = new Thread(delegate() { O.Run(copy); });
T.Start();
}
And I hope this shows where the problem is: the j
variable is captured by your anonymous method, in effect this means it is shared (by reference) by all the call-sites of O.Run()
.
No, locals are not shared between threads. If you are debugging threads be sure to open the threads window so you can switch between threads if you want to watch a variable. Otherwise you may get misleading results if the watch is stuck on one thread.
I get the following output on one run of your program, although due to it's nature you can get different results each time.
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
try this:
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();
}
}
No, neither local variables, nor method parameters are shared between threads. What you are seeing is because the variable j
is shared between the anonymous delegates you are creating. So, in your case, there is one global j
and every thread's Run()
gets the value the variable has when the method is called, which may be after the j
is incremented for the next iteration.
You can fix this by creating a new variable, that is “local” to each iteration:
for (int j = 0; j < 10; j++)
{
int tmp = j;
Thread T = new Thread(delegate() { O.Run(tmp); });
T.Start();
}
精彩评论