|
|||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionOnce you start doing multi-threaded programs, the first thing you know, you are faced with the problem of multiple threads accessing the same resource. Sometimes this can result in depressing errors. Like when two threads try to open the same file. Or when one thread is writing to a file and the other thread is trying to truncate it. You might get program crashes which is bad, and you might get a corrupted file, which is considerably worse. The .NET framework gives us the Program Listing#using <mscorlib.dll>
using namespace System;
using namespace System::Threading;
__gc class AddThread
{
public:
int x;
void Add1();
AddThread();
Thread *t1,*t2;
};
int wmain(void)
{
AddThread *a=new AddThread();
return 0;
}
AddThread::AddThread()
{
x=0;
t1=new Thread(new ThreadStart(this,&AddThread::Add1));
t2=new Thread(new ThreadStart(this,&AddThread::Add1));
t1->Name="Thread 1";
t2->Name="Thread 2";
t1->Start();
t2->Start();
}
void AddThread::Add1()
{
for (int j=0;j<10;j++)
{
for (int t=0;t<5000;t++)
x++;
//using Sleep to simulate a real-case scenario
//where heavy time-consuming calculations might be done
Thread::Sleep(5);
for (int t=0;t<5000;t++)
x--;
Console::WriteLine("{0}.....{1} has incremented x",
__box(x++),Thread::CurrentThread->Name);
}
}
Now compile and run that program. You might have expected to see numbers 0 to 19 shown on screen. Well, this is what I got. I presume you'll get something similar depending on your processor's speed and its current load. OutputD:\MyProjs\mcppthreadsync01\Debug>mcppthreadsync01.exe
5000.....Thread 1 has incremented x
5001.....Thread 2 has incremented x
5002.....Thread 1 has incremented x
5003.....Thread 2 has incremented x
5004.....Thread 1 has incremented x
5005.....Thread 2 has incremented x
5006.....Thread 1 has incremented x
5007.....Thread 2 has incremented x
5008.....Thread 1 has incremented x
5009.....Thread 2 has incremented x
5010.....Thread 1 has incremented x
5011.....Thread 2 has incremented x
5012.....Thread 2 has incremented x
5013.....Thread 1 has incremented x
5014.....Thread 2 has incremented x
15.....Thread 1 has incremented x
5016.....Thread 2 has incremented x
5017.....Thread 1 has incremented x
5018.....Thread 2 has incremented x
19.....Thread 1 has incremented x
D:\MyProjs\mcppthreadsync01\Debug>
Hmmm. Not what we wanted. Not at all! The whole problem is that one of the threads is doing something with x, just as the other thread is accessing it. So, how do we prevent that? Well, that's where the I have modified the void AddThread::Add1()
{
for (int j=0;j<10;j++)
{
Monitor::Enter(this); //added this line
for (int t=0;t<5000;t++)
x++;
Thread::Sleep(5);
for (int t=0;t<5000;t++)
x--;
Console::WriteLine("{0}.....{1} has incremented x",
__box(x++),Thread::CurrentThread->Name);
Monitor::Exit(this); //added this line
}
}
Now compile and run the program. OutputD:\MyProjs\mcppthreadsync01\Debug>mcppthreadsync01.exe
0.....Thread 1 has incremented x
1.....Thread 2 has incremented x
2.....Thread 1 has incremented x
3.....Thread 2 has incremented x
4.....Thread 1 has incremented x
5.....Thread 2 has incremented x
6.....Thread 1 has incremented x
7.....Thread 2 has incremented x
8.....Thread 1 has incremented x
9.....Thread 2 has incremented x
10.....Thread 1 has incremented x
11.....Thread 2 has incremented x
12.....Thread 1 has incremented x
13.....Thread 2 has incremented x
14.....Thread 1 has incremented x
15.....Thread 2 has incremented x
16.....Thread 1 has incremented x
17.....Thread 2 has incremented x
18.....Thread 1 has incremented x
19.....Thread 2 has incremented x
D:\MyProjs\mcppthreadsync01\Debug>
Ah! That's what we wanted. Hmm, let's take a look at how that came about. We added the following two lines.
and
From the same thread you can invoke In some cases blocking would be undesirable. In that case, you can use an
alternate call called public: static bool TryEnter(Object* obj);
This won't block but will return Let's say we want Thread 2 to finish the first six numbers before we want
thread 1 to start its work. Here we can make use of the I have modified the void AddThread::Add1()
{
for (int j=0;j<10;j++)
{
Monitor::Enter(this);
//<newly_added_block>
if(Thread::CurrentThread->Name->Equals("Thread 1"))
{
if(x<5)
Monitor::Wait(this);
}
else
{
if(x>4)
Monitor::Pulse(this);
}
//</newly_added_block>
for (int t=0;t<5000;t++)
x++;
Thread::Sleep(5);
for (int t=0;t<5000;t++)
x--;
Console::WriteLine("{0}.....{1} has incremented x",
__box(x++),Thread::CurrentThread->Name);
Monitor::Exit(this);
}
}
What Now compile and run the program. You'll get this :- D:\MyProjs\mcppthreadsync01\Debug>mcppthreadsync01.exe
0.....Thread 2 has incremented x
1.....Thread 2 has incremented x
2.....Thread 2 has incremented x
3.....Thread 2 has incremented x
4.....Thread 2 has incremented x
5.....Thread 2 has incremented x
6.....Thread 1 has incremented x
7.....Thread 2 has incremented x
8.....Thread 1 has incremented x
9.....Thread 2 has incremented x
10.....Thread 1 has incremented x
11.....Thread 2 has incremented x
12.....Thread 1 has incremented x
13.....Thread 2 has incremented x
14.....Thread 1 has incremented x
15.....Thread 1 has incremented x
16.....Thread 1 has incremented x
17.....Thread 1 has incremented x
18.....Thread 1 has incremented x
19.....Thread 1 has incremented x
There is also a Thank You
|
||||||||||||||||||||||||||||||||||||||||||||