Why do I get different value on two different computers

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 cores I always
get 100010 which is correct.
If I run this program on a computer that have two cores I sometimes get a
value that could be 96542 or 97129 or something else that less that 100010.
This is because of not doing for example lock or interlocked in this
example.

So my question is why do I always get the correct result when I run the
program on a computer with only one core ??
This computer with only one core is very old perhaps 10 years.

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
 
A

Alberto Poblacion

Tony Johansson said:
So my question is why do I always get the correct result when I run the
program on a computer with only one core ??

Probably because the switching between threads is done every 50
milliseconds or somesuch, and the loop with 10000 iterations can be
completed in less that that time. So you never get two threads to "collide"
on the Counter.count = Counter.count+1 statement.

If you want to force the issue, you can simulate a longer running
critical zone like this:

int temp = Counter.count;
System.Threading.Thread.Sleep(100);
Counter.count = temp+1;

This one should "fail" (give a result of less than 100010) even on a
single-core computer.
 
P

Patrice

Hello,
So my question is why do I always get the correct result when I run the
program on a computer with only one core ??

This is less likely but could happen (and more generally multithreading
problems are known to show up less with one core).

IMO this is because running two threads on a single core relies only on
thread switching. So you need thread switching to happen at the right time
in both threads to reveal the problem.

With a multi core system, you don't need thread switching to run those two
threads. As you removed a condition, the problem will be more likely to show
up...
 
A

Arne Vajhøj

At the bottom is a simple thread program.
If I run this program on a computer that doesn't have two cores I always
get 100010 which is correct.
If I run this program on a computer that have two cores I sometimes get a
value that could be 96542 or 97129 or something else that less that 100010.
This is because of not doing for example lock or interlocked in this
example.

So my question is why do I always get the correct result when I run the
program on a computer with only one core ??
This computer with only one core is very old perhaps 10 years.

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

As stated in a previous thread, then this code is broken and
will produce random results.

And you could get other results than 100010 on a single core
system under certain circumstances.

But you have observed a tendency to get 100010 which seems to
indicate that the threads run sequentially on a single core.

That is a very likely scenario.

A thread is kicked of the CPU/core if:
- it has used its time slice (typical 10-20 milliseconds depending
on Windows version, CPU type and task type)
- another thread has a higher priority
- this thread is waiting for something (completion of IO or sleeping)

So if you threads:
- runs in less than 10 milliseonds
- all has same priority
- do no IO or sleep
then they may very likely run sequential.

Arne
 
M

Mihajlo Cvetanović

Counter.count = Counter.count + 1;

Replace this part of the code with the following and you will get wrong
results even on computer with one core. Probably.

{
int temp = Counter.count + 1;
Thread.Sleep(10);
Counter.count = temp;
}
 
N

not_a_commie

The Thread class in .Net is not a true thread. It's more like a work
queue array in the CLR. To make a true thread in C# you have to make a
new AppDomain. The CLR pushes methods targeted for a specific
System.Thread into the real threads that it manages. And it doesn't
swap them out in the middle of an increment operation. It's not that
stupid.

Go read through this thread for more info:
http://groups.google.com/group/micr...k=gst&q=not_a_commie+monitor#995c7921d4b8e436
 
P

Peter Duniho

not_a_commie said:
The Thread class in .Net is not a true thread.

Architecturally speaking, that's correct. Practically speaking, not as
much.
It's more like a work queue array in the CLR.

In current .NET implementations I'm aware of, threads are implemented
either as true threads or fibers. I'm not even sure what you mean by
"work queue array" — it's not a standard phrase I'm familiar with, nor
one that Google is familiar with — but a .NET thread is in fact very
much like a thread in either implementation (and of course exactly like
one where true threads are used).
To make a true thread in C# you have to make a
new AppDomain.

Not true. You can use the unmanaged GetCurrentThreadId() function to
verify that on the workstation (i.e. non-server) .NET versions, when you
create a new thread, you get a new OS thread.

In any case, the threading model in .NET is well-defined and in that
model, the "thread" .NET provides is every bit as much as "real thread"
as an OS thread would be, even when they are different.
The CLR pushes methods targeted for a specific
System.Thread into the real threads that it manages. And it doesn't
swap them out in the middle of an increment operation. It's not that
stupid.

..NET doesn't do anything special with an increment operation. It
depends on how the increment is implemented by the JIT compiler. If it
uses the "inc" instruction, then a context switch isn't possible during
the increment. But if it uses "mov", "add", "mov" then the increment
can be interrupted during the operation.

In any case, .NET doesn't provide any _guarantees_ about how it will
implement an increment. C# statements like "i++", "++i", "i = i + 1",
etc. all _must_ be protected with some kind of synchronization if the
variable "i" is accessed by multiple threads.

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top