Tải bản đầy đủ - 0 (trang)
Chapter 20.  Threads and Synchronization

Chapter 20.  Threads and Synchronization

Tải bản đầy đủ - 0trang

resource.Whentheresourcebecomesfree,onepersonistaken

offthelineandgiventheresource,whichisthenlockedagain.

Attimes,variousthreadsmightwanttoaccessaresourcein

yourprogram,suchasafile.Itmightbeimportanttoensure

thatonlyonethreadhasaccesstoyourresourceatatime,and

soyouwilllocktheresource,allowathreadaccess,andthen

unlocktheresource.Programminglockscanbefairly

sophisticated,ensuringafairdistributionofresources.



20.1.Threads

Threadsaretypicallycreatedwhenyouwantaprogramtodo

twothingsatonce.Forexample,assumeyouarecalculatingpi

(3.141592653589...)tothe10billionthplace.Theprocessor

willhappilybegincomputingthis,butnothingwillwritetothe

userinterfacewhileitisworking.Becausecomputingpitothe

10billionthplacewilltakeafewmillionyears,youmightlike

theprocessortoprovideanupdateasitgoes.Inaddition,you

mightwanttoprovideaStopbuttonsothattheusercancancel

theoperationatanytime.Toallowtheprogramtohandlethe

clickontheStopbutton,youwillneedasecondthreadof

execution.

Anothercommonplacetousethreadingiswhenyoumustwait

foranevent,suchasuserinput,areadfromafile,orreceiptof

dataoverthenetwork.Freeingtheprocessortoturnits

attentiontoanothertaskwhileyouwait(suchascomputing

another10,000valuesofpi)isagoodidea,anditmakesyour

programappeartorunmorequickly.

Ontheflipside,notethatinsomecircumstances,threadingcan

actuallyslowyoudown.Assumethatinadditiontocalculating

pi,youalsowanttocalculatetheFibonacciseries

(1,1,2,3,5,8,13,21...).Ifyouhaveamultiprocessormachine,

thiswillrunfasterifeachcomputationisinitsownthread.If

youhaveasingle-processormachine(asmostusersdo),

computingthesevaluesinmultiplethreadswillcertainlyrun

slowerthancomputingoneandthentheotherinasingle

threadbecausetheprocessormustswitchbackandforth

betweenthetwothreads.Thisincurssomeoverhead.



20.1.1.StartingThreads



Thesimplestwaytocreateathreadistocreateanewinstance

oftheTHReadclass.TheThreadconstructortakesasingle

argument:adelegateinstance.TheCLRprovidesthe

THReadStartdelegateclassspecificallyforthispurpose,which

pointstoamethodyoudesignate.Thisallowsyoutoconstruct

athreadandtosaytoit,"Whenyoustart,runthismethod."

TheTHReadStartdelegatedeclarationis:

publicdelegatevoidThreadStart();



Asyoucansee,themethodyouattachtothisdelegatemust

takenoparametersandmustreturnvoid.Thus,youmight

createanewthreadlikethis:

ThreadmyThread=newThread(newThreadStart(myFunc));



Forexample,youmightcreatetwoworkerthreads,onethat

countsupfromzero:

publicvoidIncrementer()

{

for(inti=0;i<1000;i++)

{

Console.WriteLine("Incrementer:{0}",i);

}

}



andonethatcountsdownfrom1,000:

publicvoidDecrementer()

{



for(inti=1000;i>=0;i--)

{

Console.WriteLine("Decrementer:{0}",i);

}

}



Toruntheseinthreads,createtwonewthreads,eachinitialized

withaThreadStartdelegate.Theseinturnwouldbeinitialized

totherespectivememberfunctions:

Threadt1=newThread(newThreadStart(Incrementer));

Threadt2=newThread(newThreadStart(Decrementer));



Instantiatingthesethreadsdoesn'tstartthemrunning.Todoso

youmustcalltheStartmethodontheTHReadobjectitself:

t1.Start();

t2.Start();



Ifyoudon'ttakefurtheraction,thethreadstopswhenthefunction

returns.You'llseehowtostopathreadbeforethefunctionendslater

inthischapter.



Example20-1isthefullprogramanditsoutput.Youwillneed

toaddausingstatementforSystem.Threadingtomakethe

compilerawareoftheThreadclass.Noticetheoutput,where

youcanseetheprocessorswitchingfromt1tot2.



Example20-1.Usingthreads

#regionUsingdirectives

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;

usingSystem.Threading;

#endregion

namespaceUsingThreads

{

classTester

{

staticvoidMain()

{

//makeaninstanceofthisclass

Testert=newTester();

Console.WriteLine("Hello");

//runoutsidestaticMain

t.DoTest();

}

publicvoidDoTest()

{

//createathreadfortheIncrementer

//passinaThreadStartdelegate

//withtheaddressofIncrementer

Threadt1=

newThread(

newThreadStart(Incrementer));

//createathreadfortheDecrementer

//passinaThreadStartdelegate



//withtheaddressofDecrementer

Threadt2=

newThread(

newThreadStart(Decrementer));

//startthethreads

t1.Start();

t2.Start();

}

//demofunction,countsupto1K

publicvoidIncrementer()

{

for(inti=0;i<1000;i++)

{



System.Console.WriteLine(

"Incrementer:{0}",i);

}

}

//demofunction,countsdownfrom1k

publicvoidDecrementer()

{

for(inti=1000;i>=0;i--)

{

System.Console.WriteLine(

"Decrementer:{0}",i);

}

}

}

}

Output(excerpt):

Incrementer:102

Incrementer:103

Incrementer:104



Incrementer:105

Incrementer:106

Decrementer:1000

Decrementer:999

Decrementer:998

Decrementer:997



Theprocessorallowsthefirstthreadtorunlongenoughto

countupto106.Then,thesecondthreadkicksin,counting

downfrom1,000forawhile.Thenthefirstthreadisallowedto

run.WhenIrunthiswithlargernumbers,Inoticethateach

threadisallowedtorunforabout100numbersbefore

switching.



Theactualamountoftimedevotedtoanygiventhreadishandledby

thethreadscheduleranddependsonmanyfactors,suchasthe

processorspeed,demandsontheprocessorfromotherprograms,etc.



20.1.2.JoiningThreads

Whenyoutellathreadtostopprocessingandwaituntila

secondthreadcompletesitswork,youaresaidtobejoiningthe

firstthreadtothesecond.Itisasifyoutiedthetipofthefirst

threadontothetailofthesecondhence"joining"them.

Tojointhread1(t1)ontothread2(t2),write:

t2.Join();



Ifthisstatementisexecutedinamethodinthreadt1,t1will

haltandwaituntilt2completesandexits.Forexample,you

mightaskthethreadinwhichMain()executestowaitforall

ourotherthreadstoendbeforeitwritesitsconcluding

message.Inthisnextcodesnippet,assumeyou'vecreateda

collectionofthreadsnamedmyThreads.Iterateoverthe

collection,joiningthecurrentthreadtoeachthreadinthe

collectioninturn:

foreach(ThreadmyThreadinmyThreads)

{

myThread.Join();

}

Console.WriteLine("Allmythreadsaredone.");



ThefinalmessageAllmythreadsaredoneisn'tbeprinted

untilallthethreadshaveended.Inaproductionenvironment,

youmightstartupaseriesofthreadstoaccomplishsometask

(e.g.,printing,updatingthedisplay,etc.)andnotwantto

continuethemainthreadofexecutionuntiltheworkerthreads

arecompleted.



20.1.3.BlockingThreadswithSleep

Attimes,youwanttosuspendyourthreadforashortwhile.

Youmight,forexample,likeyourclockthreadtosuspendfor

aboutasecondinbetweentestingthesystemtime.Thislets

youdisplaythenewtimeaboutonceasecondwithoutdevoting

hundredsofmillionsofmachinecyclestotheeffort.

TheTHReadclassoffersapublicstaticmethod,Sleep,forjust

thispurpose.Themethodisoverloaded;oneversiontakesan



int,theotheratimeSpanobject.Eachrepresentsthenumber

ofmillisecondsyouwantthethreadsuspendedfor,expressed

eitherasanint(e.g.,2,000=2,000millisecondsor2seconds)

orasatimeSpan.

AlthoughtimeSpanobjectscanmeasureticks(100

nanoseconds),theSleep()method'sgranularityisin

milliseconds(1,000,000nanoseconds).

Tocauseyourthreadtosleepforonesecond,youcaninvoke

thestaticmethodofTHRead.Sleep,whichsuspendsthethread

inwhichitisinvoked:

Thread.Sleep(1000);



Attimes,you'llpasszerofortheamountoftimetosleep;this

signalsthethreadschedulerthatyou'dlikeyourthreadtoyield

toanotherthread,evenifthethreadschedulermightotherwise

giveyourthreadabitmoretime.

IfyoumodifyExample20-1toaddaThread.Sleep(1)

statementaftereachWriteLine(),theoutputchanges

significantly:

for(inti=0;i<1000;i++)

{

Console.WriteLine(

"Incrementer:{0}",i);

Thread.Sleep(1);

}



Thissmallchangeissufficienttogiveeachthreadan

opportunitytorunoncetheotherthreadprintsonevalue.The



outputreflectsthischange:

Incrementer:0

Incrementer:1

Decrementer:1000

Incrementer:2

Decrementer:999

Incrementer:3

Decrementer:998

Incrementer:4

Decrementer:997

Incrementer:5

Decrementer:996

Incrementer:6

Decrementer:995



20.1.4.KillingThreads

Typically,threadsdieafterrunningtheircourse.Youcan,

however,askathreadtokillitself.Thecleanestwayistoseta

KeepAliveBooleanflagthatthethreadcancheckperiodically.

Whentheflagchangesstate(e.g.,goesfromtruetofalse)the

threadcanstopitself.

AnalternativeistocallThread.Interruptwhichasksthe

threadtokillitself.Finally,indesperation,andifyouare

shuttingdownyourapplicationinanycase,youmaycall

Thread.Abort.ThiscausesaThreadAbortExceptionexception

tobethrown,whichthethreadcancatch.

ThethreadoughttotreattheTHReadAbortExceptionexception

asasignalthatitistimetoexitimmediately.Inanycase,you

don'tsomuchkillathreadaspolitelyrequestthatitcommit

suicide.



Youmightwishtokillathreadinreactiontoanevent,suchas

theuserclickingtheCancelbutton.Theeventhandlerforthe

Cancelbuttonmightbeinthreadt1,andtheeventitis

cancelingmightbeinthreadt2.Inyoureventhandler,youcan

callAbortont1:

t1.Abort();



Anexceptionwillberaisedint1'scurrentlyrunningmethod

thatt1cancatch.

InExample20-2,threethreadsarecreatedandstoredinan

arrayofTHReadobjects.BeforetheTHReadsarestarted,the

IsBackgroundpropertyissettoTRue(backgroundthreadsare

exactlylikeforegroundthreads,exceptthattheydon'tstopa

processfromterminating).Eachthreadisthenstartedand

named(e.g.,Thread1,THRead2,etc.).Amessageisdisplayed

indicatingthatthethreadisstarted,andthenthemainthread

sleepsfor50millisecondsbeforestartingupthenextthread.

Afterallthreethreadsarestartedandanother50milliseconds

havepassed,thefirstthreadisabortedbycallingAbort().The

mainthreadthenjoinsallthreeoftherunningthreads.The

effectofthisisthatthemainthreadwillnotresumeuntilallthe

otherthreadshavecompleted.Whentheydocomplete,the

mainthreadprintsamessage:AllmytHReadsaredone.The

completesourceisdisplayedinExample20-2.



Example20-2.Interruptingathread

#regionUsingdirectives

usingSystem;

usingSystem.Collections.Generic;



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Chapter 20.  Threads and Synchronization

Tải bản đầy đủ ngay(0 tr)

×