GentooPOSIX threads explained part 3.docx
- 文档编号:25221233
- 上传时间:2023-06-06
- 格式:DOCX
- 页数:16
- 大小:21.41KB
GentooPOSIX threads explained part 3.docx
《GentooPOSIX threads explained part 3.docx》由会员分享,可在线阅读,更多相关《GentooPOSIX threads explained part 3.docx(16页珍藏版)》请在冰豆网上搜索。
GentooPOSIXthreadsexplainedpart3
Disclaimer:
TheoriginalversionofthisarticlewasfirstpublishedonIBMdeveloperWorks,andispropertyofWesttechInformationServices.Thisdocumentisanupdatedversionoftheoriginalarticle,andcontainsvariousimprovementsmadebytheGentooLinuxDocumentationteam.
Thisdocumentisnotactivelymaintained.
POSIXthreadsexplained,part3
窗体顶端
Content:
窗体底端
1. Improveefficiencywithconditionvariables
Conditionvariablesexplained
Iendedmypreviousarticlebydescribingaparticulardilemmahowdoesathreaddealwithasituationwhereitiswaitingforaspecificconditiontobecometrue?
Itcouldrepeatedlylockandunlockamutex,eachtimecheckingashareddatastructureforacertainvalue.Butthisisawasteoftimeandresources,andthisformofbusypollingisextremelyinefficient.Thebestwaytodothisistousethepthread_cond_wait()calltowaitonaparticularconditiontobecometrue.
It'simportanttounderstandwhatpthread_cond_wait()does--it'stheheartofthePOSIXthreadssignallingsystem,andalsothehardestparttounderstand.
First,let'sconsiderascenariowhereathreadhaslockedamutex,inordertotakealookatalinkedlist,andthelisthappenstobeempty.Thisparticularthreadcan'tdoanything--it'sdesignedtoremoveanodefromthelist,andtherearenonodesavailable.So,thisiswhatitdoes.
Whilestillholdingthemutexlock,ourthreadwillcallpthread_cond_wait(&mycond,&mymutex).Thepthread_cond_wait()callisrathercomplex,sowe'llstepthrougheachofitsoperationsoneatatime.
Thefirstthingpthread_cond_wait()doesissimultaneouslyunlockthemutexmymutex(sothatotherthreadscanmodifythelinkedlist)andwaitontheconditionmycond(sothatpthread_cond_wait()willwakeupwhenitis"signalled"byanotherthread).Nowthatthemutexisunlocked,otherthreadscanaccessandmodifythelinkedlist,possiblyaddingitems.
Atthispoint,thepthread_cond_wait()callhasnotyetreturned.Unlockingthemutexhappensimmediately,butwaitingontheconditionmycondisnormallyablockingoperation,meaningthatourthreadwillgotosleep,consumingnoCPUcyclesuntilitiswokenup.Thisisexactlywhatwewanttohappen.Ourthreadissleeping,waitingforaparticularconditiontobecometrue,withoutperforminganykindofbusypollingthatwouldwasteCPUtime.Fromourthread'sperspective,it'ssimplywaitingforthepthread_cond_wait()calltoreturn.
Now,tocontinuetheexplanation,let'ssaythatanotherthread(callit"thread2")locksmymutexandaddsanitemtoourlinkedlist.Immediatelyafterunlockingthemutex,thread2callsthefunctionpthread_cond_broadcast(&mycond).Bydoingso,thread2willcauseallthreadswaitingonthemycondconditionvariabletoimmediatelywakeup.Thismeansthatourfirstthread(whichisinthemiddleofapthread_cond_wait()call)willnowwakeup.
Now,let'stakealookatwhathappenstoourfirstthread.Afterthread2calledpthread_cond_broadcast(&mymutex)youmightthinkthatthread1'spthread_cond_wait()willimmediatelyreturn.Notso!
Instead,pthread_cond_wait()willperformonelastoperation:
relockmymutex.Oncepthread_cond_wait()hasthelock,itwillthenreturnandallowthread1tocontinueexecution.Atthatpoint,itcanimmediatelycheckthelistforanyinterestingchanges.
Stopandreview!
CodeListing 1.1:
queue.h
/*queue.h
**Copyright2000DanielRobbins,GentooTechnologies,Inc.
**Author:
DanielRobbins
**Date:
16Jun2000
*/
typedefstructnode{
structnode*next;
}node;
typedefstructqueue{
node*head,*tail;
}queue;
voidqueue_init(queue*myroot);
voidqueue_put(queue*myroot,node*mynode);
node*queue_get(queue*myroot);
CodeListing 1.2:
queue.c
/*queue.c
**Copyright2000DanielRobbins,GentooTechnologies,Inc.
**Author:
DanielRobbins
**Date:
16Jun2000
**
**Thissetofqueuefunctionswasoriginallythread-aware.I
**redesignedthecodetomakethissetofqueueroutines
**thread-ignorant(justageneric,boringyetveryfastsetofqueue
**routines).Whythechange?
Becauseitmakesmoresensetohave
**thethreadsupportasanoptionaladd-on.Considerasituation
**whereyouwanttoadd5nodestothequeue.Withthe
**thread-enabledversion,eachcalltoqueue_put()would
**automaticallylockandunlockthequeuemutex5times--that'sa
**lotofunnecessaryoverhead.However,bymovingthethreadstuff
**outofthequeueroutines,thecallercanlockthemutexonceat
**thebeginning,theninsert5items,andthenunlockattheend.
**Movingthelock/unlockcodeoutofthequeuefunctionsallowsfor
**optimizationsthataren'tpossibleotherwise.Italsomakesthis
**codeusefulfornon-threadedapplications.
**
**Wecaneasilythread-enablethisdatastructurebyusingthe
**data_controltypedefinedincontrol.candcontrol.h.*/
#include
#include"queue.h"
voidqueue_init(queue*myroot){
myroot->head=NULL;
myroot->tail=NULL;
}
voidqueue_put(queue*myroot,node*mynode){
mynode->next=NULL;
if(myroot->tail!
=NULL)
myroot->tail->next=mynode;
myroot->tail=mynode;
if(myroot->head==NULL)
myroot->head=mynode;
}
node*queue_get(queue*myroot){
//getfromroot
node*mynode;
mynode=myroot->head;
if(myroot->head!
=NULL)
myroot->head=myroot->head->next;
returnmynode;
}
CodeListing 1.3:
control.h
#include
typedefstructdata_control{
pthread_mutex_tmutex;
pthread_cond_tcond;
intactive;
}data_control;
CodeListing 1.4:
control.c
/*control.c
**Copyright2000DanielRobbins,GentooTechnologies,Inc.
**Author:
DanielRobbins
**Date:
16Jun2000
**
**Theseroutinesprovideaneasywaytomakeanytypeof
**data-structurethread-aware.Simplyassociateadata_control
**structurewiththedatastructure(bycreatinganewstruct,for
**example).Then,simplylockandunlockthemutex,or
**wait/signal/broadcastontheconditionvariableinthedata_control
**structureasneeded.
**
**data_controlstructscontainanintcalled"active".Thisintis
**intendedtobeusedforaspecifickindofmultithreadeddesign,
**whereeachthreadchecksthestateof"active"everytimeitlocks
**themutex.Ifactiveis0,thethreadknowsthatinsteadofdoing
**itsnormalroutine,itshouldstopitself.Ifactiveis1,it
**shouldcontinueasnormal.So,bysettingactiveto0,a
**controllingthreadcaneasilyinformathreadworkcrewtoshut
**downinsteadofprocessingnewjobs.Usethecontrol_activate()
**andcontrol_deactivate()functions,whichwillalsobroadcaston
**thedata_controlstruct'sconditionvariable,sothatallthreads
**stuckinpthread_cond_wait()willwakeup,haveanopportunityto
**noticethechange,andthenterminate.
*/
#include"control.h"
intcontrol_init(data_control*mycontrol){
intmystatus;
if(pthread_mutex_init(&(mycontrol->mutex),NULL))
return1;
if(pthread_cond_init(&(mycontrol->cond),NULL))
return1;
mycontrol->active=0;
return0;
}
intcontrol_destroy(data_control*mycontrol){
intmystatus;
if(pthread_cond_destroy(&(mycontrol->cond)))
return1;
if(pthread_mutex_destroy(&(mycontrol->cond)))
return1;
mycontrol->active=0;
return0;
}
intcontrol_activate(data_control*mycontrol){
intmystatus;
if(pthread_mutex_lock(&(mycontrol->mutex)))
return0;
mycontrol->active=1;
pthread_mutex_unlock(&(mycontrol->mutex));
pthread_cond_broadcast(&(mycontrol->cond));
return1;
}
intcontrol_deactivate(data_control*mycontrol){
intmystatus;
if(pthread_mutex_lock(&(mycontrol->mutex)))
return0;
mycontrol->active=0;
pthread_mutex_unlock(&(mycontrol->mutex));
pthread_cond_broadcast(&(mycontrol->cond));
return1;
}
Debugtime
Onemoremiscellaneousfilebeforewegettothebiggie.Here'sdbug.h:
CodeListing 1.5:
dbug.h
#definedabort()\
{printf("Abortingatline%dinsourcefile%s\n",__LINE__,__FILE__);abort();}
Weusethiscodetohandleunrecoverableerrorsinourworkcrewcode.
Theworkcrewcode
Speakingoftheworkcrewcode,hereitis:
CodeListing 1.6:
workcrew.c>
#include
#include
#include"control.h"
#include"queue.h"
#include"dbug.h"
/*thework_queueholdstasksforthevariousthreadstocomplete.*/
structwork_queue{
data_controlcontrol;
queuework;
}wq;
/*Iaddedajobnumbertotheworknode.Normally,theworknode
wouldcontainadditionaldatathatneededtobeprocessed.*/
typedefstructwork_node{
structnode*next;
intjobnum;
}wnode;
/*thecleanupqueueholdsstoppedthreads.Beforeathread
terminates,itaddsitselftothislist.Sincethemainthreadis
waitingforchangesinthislist,itwillthenwakeupandcleanup
thenewlyterminatedthread.*/
structcleanup_queue{
data_controlcontrol;
queuecleanup;
}cq;
/*Iaddedathreadnumber(fordebugging/instructionalpurposes)and
athreadidtothecleanupnode.Thecleanupnodegetspassedto
thenewthreadonstartup,andjustbeforethethreadstops,it
attachesthecleanupnodetothecleanupqueue.Themainthread
monitorsthecleanupqueueandistheonethatperformsthe
necessarycleanup.*/
typedefstructcleanup_node{
structnode*next;
intthreadnum;
pthread_ttid;
}cnode;
void*threadfunc(void*myarg){
wnode*mywork;
cnode*mynode;
mynode=(cnode*)myarg;
pthread_mutex_lock(&wq.control.mutex);
while(wq.control.active){
while(wq.work.head==NULL&&wq.control.active){
pthread_cond_wait(&wq.control.cond,&wq.control.mutex);
}
if(!
wq.control.active)
break;
//wegotsomething!
mywork=(wnode*)queue_get(&wq.work);
pthread_mutex_unlock(&wq.control.mutex
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- GentooPOSIX threads explained part