Intorduction: Theading for beginers.
Hey all , many of us are a great software engineer, anyway
I noticed a fact that many of us are not well aware the
great present that the operating system gave to us. Yes
right , this present name is MultiThreading Enviroment ,
For some people those words are a nightmare , and for
others this isue does not tell too much , many of us have
never heard about MultiThreading.
This article is for beginners mainly and for those who does
not understand the concept of Multithreding,
Part one: What is thread,
Thread is a set of the following
{ ProgramCounter,Stack,Cpu} , the normal program that we
are used to has one thread which is the main thread. What
that we want to do is to add to our program one more thread
.
We will see code example which will create a simple thread
,
This is the function that will run as a thread:
<BR><BR>void Thread1(int * a_iNum)<BR>{<BR> while(*a_iNum>0)<BR> {<BR> cout<<*a_iNum<<" ";<BR> (*a_iNum)--;<BR> }<BR>}<BR>
This is the function that will create the thread:
<BR><BR>void RunThread1()<BR>{<BR> int l_iNum=10;<BR> HANDLE <BR><BR>l_htRun=::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Threa<BR><BR>d1,&l_iNum,0,0);<BR><BR> if(l_htRun==NULL)<BR> {<BR> cout<<"cout could not run the thread \n";<BR> return;<BR> }<BR><BR> WaitForSingleObject(l_htRun,INFINITE);<BR><BR> cout<<"The thread was finished \n";<BR>}<BR>
As we can see , this thread is not doing anything special
, The target is to learn the API of creating the thread ,
I would like to explain few things now ,
LPTHREAD_START_ROUTINE - this is a typedef to function,
In windows header files it looks like that ,
typedef int (*LPTHREAD_START_ROUTINE)(void*);
(LPTHREAD_START_ROUTINE)Thread1 - that means that we are
making a casting to the function type so that it will be
compatible and the code will be compiled weill.
The fourth parameter is the pointer to the argument that we
want to pass to the thread.
I will not discuss about the other parameters now, we will
discuss about them later.
We can see that the function of CreateThread returns type
HANDLE , and what that we are doing with this HANDLE is to
wait untill that the thread will be finished .
So what that we learned untill now that this is verry easy
to CreateThread , we did not learn yet anything interesting
but for the begining this is O.K.
The example that I will show not is verry important for the
THREAD CONCEPT UNDERSTANDING.
<BR><BR>void Thread2(int * a_pNum)<BR>{<BR> while(*a_pNum)<BR> {<BR> cout<<"A";<BR> cout.flush();<BR> ::Sleep(100);<BR> }<BR><BR>}<BR><BR>void Thread3(int * a_pNum)<BR>{<BR> while(*a_pNum)<BR> {<BR> cout<<"B";<BR> cout.flush();<BR> ::Sleep(100);<BR> }<BR>}<BR><BR> <BR><BR><BR>void RunThread2AndThread3()<BR>{<BR> int a_iNum2=1;<BR> int a_iNum3=1;<BR> <BR> HANDLE l_hArr[2];<BR> l_hArr[0]<BR><BR>=::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread2,&a_i<BR><BR>Num2,0,0);<BR> l_hArr[1]<BR><BR>=::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread3,&a_i<BR><BR>Num3,0,0);<BR><BR><BR> WaitForMultipleObjects(2,l_hArr,true,INFINITE);<BR><BR>}<BR>
what that we can see in this example is 2 thread that are
running , One of them print A and the second Print B to the
scree.
When I was lecturing about threading ,one of my student
asked me "What about this code?"
<BR><BR>void SeeTheProblem()<BR>{<BR> int a_iNum2=1;<BR> int a_iNum3=1;<BR><BR> Thread2(&a_iNum2);<BR> a_iNum2=0;<BR> Thread3(&a_iNum3);<BR> a_iNum3=0;<BR> <BR>}<BR>
It will do the same work , wont it ?
As we can all see this this function will not do the work
as we can see the thread will get stuck in the minute it
will enter to the function name Thread2 and it will not
pass this line , since that this function is infinite.
However , When we run the function as a thread it will run
because that the thread is running on a different CPU.
Comment:
1.The sleep function which I added is not that important ,
if I would not have added it the result was that the cpu of
Ur computer will be 100% .
2.The .flush() of the cout is in order to flush the date to
the screen , as we all know cout does not print immidiately
to the screen , only when its buffer is full therefore I
had to flush the date in order to show , this was only for
the example try not to use flush function in run time code
since it is not effective .
Thirth Part , Using Global Variable ,
As we all know all threads from one process have access to
the data segment of the process or in other words they can
access global varible , this is one of the advantage of the
threads and one of the problem ( for programmers) as well.
<BR><BR>int g_iGoOn=1;<BR><BR>void Thread4(int * a_iNum)<BR>{<BR> while(g_iGoOn)<BR> {<BR> cout<<*a_iNum<<"\n";<BR> ::Sleep(5);<BR> }<BR><BR>}<BR><BR> <BR><BR> <BR><BR><BR>void RunThread4()<BR>{<BR> HANDLE l_hArr[2];<BR> int a_iNum1=10;<BR> int a_iNum2=11;<BR> l_hArr[0]<BR><BR>=::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread4,&a_i<BR><BR>Num1,0,0);<BR> l_hArr[1]<BR><BR>=::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread5,&a_i<BR><BR>Num2,0,0);<BR><BR><BR> ::Sleep(5000);<BR> g_iGoOn=0;<BR><BR> WaitForMultipleObjects(2,l_hArr,true,INFINITE);<BR><BR><BR>}<BR><BR>
In this code we can see how that the thread are using the
global variables in order to check wethear to continue or
to stop their activity.
Those example are verry simple , the target is to show the
user how simple is it to write code ,
View the second part of this article in order to see
Syncronizations problems and solutions ,
In the next article we will discuss more about the functions :
WaitForSingleObject , WaitForMultipleObject , mutex,event , semaphore,