T
Tony Johansson
Hi!
At the bottom is a simple thread program.
If I run this program on a computer that doesn't have two kernels I always
get 100010 which is correct.
If I run this program on a computer that have two kernels I sometimes get a
value that could be 96542 or 97129 or something else that less that 100010.
The book explaination to this is the following.
"This happens because of the way that updating the Cound field works on the
processor. On most computers, this code resolve into three steps.
1. Load the value into a register inside the processor.
2. Increment the value in the register.
3. Copy the value from the register back to memory.
The problem is that in threaded code all these three steps are treated as
atomic operation. Two threads could each read the value from memory and at
the same time update them with the same updated value. This is why the code
just loses some counts.
Here is the MSDN docs explanation why you must for example use the
Interlocked solution
The Increment and Decrement methods increment or decrement a variable and
store the resulting value in a single operation. On most computers,
incrementing a variable is not an atomic operation, requiring the following
steps:
Load a value from an instance variable into a register.
Increment or decrement the value.
Store the value in the instance variable.
If you do not use Increment and Decrement, a thread can be preempted after
executing the first two steps. Another thread can then execute all three
steps. When the first thread resumes execution, it overwrites the value in
the instance variable, and the effect of the increment or decrement
performed by the second thread is lost.
My comment is that I would says that MSDN docs is correct saying
a thread can be preempted after executing the first two steps. Another
thread can then execute all three steps. When the first thread resumes
execution, it overwrites the value in the instance variable, and the effect
of the increment or decrement performed by the second thread is lost.
So my question is that is the book wrong when it say that Two threads could
each read the value from memory and at the same time update them with the
same updated value. This is why the code just loses some counts.
I mean that the pre-emptive multitasking mechanism is still being used so
you can only have one thread being executed while the other is waiting for a
timeslice.
Class Test
{
static void UpdateCount()
{
for (int x = 0; x <= 10000; x++)
Counter.count = Counter.count + 1;
}
public static void Main()
{
ThreadStart starter = new ThreadStart(UpdateCount);
Thread[] threads = new Thread[10];
for (int x = 0; x < 10; x++)
{
threads[x] = new Thread(starter);
threads[x].Start();
}
for (int x = 0; x < 10; x++)
{
threads[x].Join();
}
Console.WriteLine("Total: {0}", Counter.count);
Console.ReadLine();
}
}
//Tony
At the bottom is a simple thread program.
If I run this program on a computer that doesn't have two kernels I always
get 100010 which is correct.
If I run this program on a computer that have two kernels I sometimes get a
value that could be 96542 or 97129 or something else that less that 100010.
The book explaination to this is the following.
"This happens because of the way that updating the Cound field works on the
processor. On most computers, this code resolve into three steps.
1. Load the value into a register inside the processor.
2. Increment the value in the register.
3. Copy the value from the register back to memory.
The problem is that in threaded code all these three steps are treated as
atomic operation. Two threads could each read the value from memory and at
the same time update them with the same updated value. This is why the code
just loses some counts.
Here is the MSDN docs explanation why you must for example use the
Interlocked solution
The Increment and Decrement methods increment or decrement a variable and
store the resulting value in a single operation. On most computers,
incrementing a variable is not an atomic operation, requiring the following
steps:
Load a value from an instance variable into a register.
Increment or decrement the value.
Store the value in the instance variable.
If you do not use Increment and Decrement, a thread can be preempted after
executing the first two steps. Another thread can then execute all three
steps. When the first thread resumes execution, it overwrites the value in
the instance variable, and the effect of the increment or decrement
performed by the second thread is lost.
My comment is that I would says that MSDN docs is correct saying
a thread can be preempted after executing the first two steps. Another
thread can then execute all three steps. When the first thread resumes
execution, it overwrites the value in the instance variable, and the effect
of the increment or decrement performed by the second thread is lost.
So my question is that is the book wrong when it say that Two threads could
each read the value from memory and at the same time update them with the
same updated value. This is why the code just loses some counts.
I mean that the pre-emptive multitasking mechanism is still being used so
you can only have one thread being executed while the other is waiting for a
timeslice.
Class Test
{
static void UpdateCount()
{
for (int x = 0; x <= 10000; x++)
Counter.count = Counter.count + 1;
}
public static void Main()
{
ThreadStart starter = new ThreadStart(UpdateCount);
Thread[] threads = new Thread[10];
for (int x = 0; x < 10; x++)
{
threads[x] = new Thread(starter);
threads[x].Start();
}
for (int x = 0; x < 10; x++)
{
threads[x].Join();
}
Console.WriteLine("Total: {0}", Counter.count);
Console.ReadLine();
}
}
//Tony