I'm probably missing something basic here, but still would appreciate your kind help in understanding this. So I have the following simple multithreaded program I wrote:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
// List<int> outcome = new List<int>();
Test t = new Test();
Thread thread1 = new Thread(new ThreadStart(t.call1));
Thread thread2 = new Thread(new ThreadStart(t.call2));
thread1.Start();
thread2.Start();
Thread.Sleep(3000); //Give enough time for threads to end
Console.Write("{0},", t.mSum);
t.mSum = 0;
}
}
class Test
{
public int mSum = 0;
public void call1()
{
//lock (this)
//{
for (int i = 0; i < 100; i++)
{
Console.WriteLine("Hello Thread 1, mSum value: {0}", mSum);
mSum = mSum + 1;
Console.WriteLine("Goodbye Thread 1, mSum value: {0}", mSum);
}
//}
// Console.WriteLine(mSum);
}
public void call2()
{
for (int i = 0; i < 100 ; i++)
{
Console.WriteLine("Hello Thread 2, mSum value: {0}",mSum);
mSum = mSum + 1;
Console.WriteLine("Goodbye Thread 2, mSum value: {0}",mSum);
}
}
}
}
So I would expect this output to be nondetermenistic because context switching can occur anytime right? But when I run the program, I get the following output (only a part of the output, malformed due to my poor stackoverflow.com question posting skills):
Hello Thread 1, mSum value: 62 Goodbye Thread 1, mSum value: 63 Hello Thread 1, mSum value: 63 Goodbye Thread 1, mSum value: 64 Hello Thread 2, mSum value: 59 Goodbye Thread 2, mSum value: 65 Hello Thread 2, mSum value: 65 Goodbye Thread 2, mSum value: 66
So, assuming I wrote this right, and mSum is indeed shared between the threads (looks like it...) - how can I explain line no. 3? Thread 2 reads 59, adds 1 and then we get 65!
Did I discover a new kind of math? :)
C Introduction C is a general-purpose programming language created by Dennis Ritchie at the Bell Laboratories in 1972. It is a very popular language, despite being old. C is strongly associated with UNIX, as it was developed to write the UNIX operating system.
We can say that C is a hands-on language and we can program it in whichever way we want. C++ consists of some high-level object-oriented programming constructs that help us to code high-level programs. Thus if we say C is easy then C++ is also easier to code.
While C is one of the more difficult languages to learn, it's still an excellent first language pick up because almost all programming languages are implemented in it. This means that once you learn C, it'll be simple to learn more languages like C++ and C#.
You're not locking the shared variable mSum
, and mSum = mSum + 1
is not an atomic operation. And it should be obvious that printing to console, incrementing a variable and then printing to console again is not atomic all the more :) There are many possible ways the threads may interlace. For example:
1) mSum = 0 [Thread1 is working]
2) mSum = 1 [Thread1 is working]
3) mSum = 2 [Thread2 is working]
4) ...
5) mSum = 59 [Thread2 is working] and it gets pre-empted after "Hello..."
6) mSum = 60 [Thread1 is working]
7) mSum = 61 [Thread1 is working]
8) ...
9) mSum = 64 [Thread2 is working] awaken just before incrementation line Thread2 continues, and calculates 65
In 5)
Thread2
could've been pre-empted even after reading mSum from memory in mSum = mSum + 1
but before calculating mSum + 1
.
Because you are using multiple threads, the value may well have changed between the first and second Console.WriteLine
call.
If you want to make sure you are reporting the correct value that the addition will use, you'll have to use a lock.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With