sync.Mutex互斥锁多个groutine在同一时间只能有一个获取到互斥锁
二:读写都有 //不加锁的话有可能是读的错误的值 funcread(){ deferrwL.RUnlock() rwL.RLock() fmt.Println("read",m[0]) } //如果不加锁会报错fatalerror:concurrentmapwrites funcwrite(){ deferrwL.Unlock() rwL.Lock() m[0]=m[0]+1 } funcrwLock(){ fori:=0;i<10000;i++{ goread() } fori:=0;i<10000;i++{ gowrite() } } funcmain(){ //vari() //mp() rwLock() time.Sleep(3*time.Second) }同时只能有一个goroutine能够获得写锁定同时可以有任意多个gorouinte获得读锁定同时只能存在写锁定或读锁定(读和写互斥)。
一:Question Whenmorethanonethread*needstomutatethesamevalue,alockingmechanismisneededtosynchronizesaccess. Withoutittwoormorethreads*couldbewritingtothesamevalueatthesametime,resultingincorruptmemory thattypicallyresultsinacrash. Theatomicpackageprovidesafastandeasywaytosynchronizeaccesstoprimitivevalues.Foracounteritisthefastestsynchronizationmethod. Ithasmethodswithwelldefinedusecases,suchasincrementing,decrementing,swapping,etc. Thesyncpackageprovidesawaytosynchronizeaccesstomorecomplicatedvalues,suchasmaps,slices,arrays,orgroupsofvalues. Youusethisforusecasesthatarenotdefinedinatomic. Ineithercaselockingisonlyrequiredwhenwriting.Multiplethreads*cansafelyreadthesamevaluewithoutalockingmechanism. 1.Letstakealookatthecodeyouprovided. typeStatstruct{ countersmap[string]*int64 countersLocksync.RWMutex averagesmap[string]*int64 averagesLocksync.RWMutex } func(s*Stat)Count(namestring){ s.countersLock.RLock() counter:=s.counters[name] s.countersLock.RUnlock() ifcounter!=nil{ atomic.AddInt64(counter,int64(1)) return } } 2.Whatsmissinghereishowthemapsthemselvesareinitialized.Andsofarthemapsarenotbeingmutated.Ifthecounternamesarepredeterminedandcannotbeaddedtolater,youdontneedtheRWMutex.Thatcodemightlooksomethinglikethis: typeStatstruct{ countersmap[string]*int64 } funcInitStat(names...string)Stat{ counters:=make(map[string]*int64) for_,name:=rangenames{ counter:=int64(0) counters[name]=&counter } returnStat{counters} } func(s*Stat)Count(namestring)int64{ counter:=s.counters[name] ifcounter==nil{ return-1//(int64,error)instead? } returnatomic.AddInt64(counter,1) }(Note:Iremovedaveragesbecauseitwasntbeingusedintheoriginalexample.)
Now,letssayyoudidntwantyourcounterstobepredetermined.Inthatcaseyouwouldneedamutextosynchronizeaccess.
3.LetstryitwithjustaMutex.Itssimplebecauseonlyonethread*canholdLockatatime.Ifasecondthread*triestoLockbeforethefirstreleasestheirswithUnlock,itwaits(orblocks)**untilthen. typeStatstruct{ countersmap[string]*int64 mutexsync.Mutex } funcInitStat()Stat{ returnStat{counters:make(map[string]*int64)} } func(s*Stat)Count(namestring)int64{ s.mutex.Lock() counter:=s.counters[name] ifcounter==nil{ value:=int64(0) counter=&value s.counters[name]=counter } s.mutex.Unlock() returnatomic.AddInt64(counter,1) } 二:Thecodeabovewillworkjustfine.Buttherearetwoproblems. 1.IfthereisapanicbetweenLock()andUnlock()themutexwillbelockedforever,evenifyouweretorecoverfromthepanic.Thiscodeprobablywontpanic,butingeneralitsbetterpracticetoassumeitmight.Problem#1iseasytosolve.Usedefer:
``` func(s*Stat)Count(namestring)int64{ s.mutex.Lock() defers.mutex.Unlock() counter:=s.counters[name] ifcounter==nil{ value:=int64(0) counter=&value s.counters[name]=counter } returnatomic.AddInt64(counter,1) } ```ThisensuresthatUnlock()isalwayscalled.Andifforsomereasonyouhavemorethenonereturn,youonlyneedtospecifyUnlock()onceattheheadofthefunction.
2.Anexclusivelockistakenwhilefetchingthecounter.Onlyonethread*canreadfromthecounteratonetime. Problem#2canbesolvedwithRWMutex.Howdoesitworkexactly,andwhyisituseful? RWMutexisanextensionofMutexandaddstwomethods:RLockandRUnlock.ThereareafewpointsthatareimportanttonoteaboutRWMutex: RLockisasharedreadlock.Whenalockistakenwithit,otherthreads*canalsotaketheirownlockwithRLock.Thismeansmultiplethreads*canreadatthesametime.Itssemi-exclusive. Ifthemutexisreadlocked,acalltoLockisblocked**.Ifoneormorereadersholdalock,youcannotwrite. Ifthemutexiswritelocked(withLock),RLockwillblock**. AgoodwaytothinkaboutitisRWMutexisaMutexwithareadercounter.RLockincrementsthecounterwhileRUnlockdecrementsit.AcalltoLockwillblockaslongasthatcounteris>0. Youmaybethinking:Ifmyapplicationisreadheavy,wouldthatmeanawritercouldbeblockedindefinitely?No.ThereisonemoreusefulpropertyofRWMutex: Ifthereadercounteris>0andLockiscalled,futurecallstoRLockwillalsoblockuntiltheexistingreadershavereleasedtheirlocks,thewriterhasobtainedhislockandlaterreleasesit. Thinkofitasthelightabovearegisteratthegrocerystorethatsaysacashierisopenornot.Thepeopleinlinegettostaythereandtheywillbehelped,butnewpeoplecannotgetinline.Assoonasthelastremainingcustomerishelpedthecashiergoesonbreak,andthatregistereitherremainscloseduntiltheycomebackortheyarereplacedwithadifferentcashier. 3.LetsmodifytheearlierexamplewithanRWMutex: typeStatstruct{ countersmap[string]*int64 mutexsync.RWMutex } funcInitStat()Stat{ returnStat{counters:make(map[string]*int64)} } func(s*Stat)Count(namestring)int64{ varcounter*int64 ifcounter=getCounter(name);counter==nil{ counter=initCounter(name); } returnatomic.AddInt64(counter,1) } func(s*Stat)getCounter(namestring)*int64{ s.mutex.RLock() defers.mutex.RUnlock() returns.counters[name] } func(s*Stat)initCounter(namestring)*int64{ s.mutex.Lock() defers.mutex.Unlock() counter:=s.counters[name] ifcounter==nil{ value:=int64(0) counter=&value s.counters[name]=counter } returncounter } 三:WiththecodeaboveIveseparatedthelogicoutintogetCounterandinitCounterfunctionsto:Keepthecodesimpletounderstand.ItwouldbedifficulttoRLock()andLock()inthesamefunction.
Releasethelocksasearlyaspossiblewhileusingdefer.
Thecodeabove,unliketheMutexexample,allowsyoutoincrementdifferentcounterssimultaneously.AnotherthingIwantedtopointoutiswithalltheexamplesabove,themapmap[string]*int64containspointerstothecounters,notthecountersthemselves.Ifyouweretostorethecountersinthemapmap[string]int64youwouldneedtouseMutexwithoutatomic.Thatcodewouldlooksomethinglikethis:
typeStatstruct{ countersmap[string]int64 mutexsync.Mutex } funcInitStat()Stat{ returnStat{counters:make(map[string]int64)} } func(s*Stat)Count(namestring)int64{ s.mutex.Lock() defers.mutex.Unlock() s.counters[name]++ returns.counters[name] }Youmaywanttodothistoreducegarbagecollection-butthatwouldonlymatterifyouhadthousandsofcounters-andeventhenthecountersthemselvesdonttakeupawholelotofspace(comparedtosomethinglikeabytebuffer).
WhenIsaythreadImeango-routine.Athreadinotherlanguagesisamechanismforrunningoneormoresetsofcodesimultaneously.Athreadisexpensivetocreateandtear-down.Ago-routineisbuiltontopofthreads,butre-usesthem.Whenago-routinesleepstheunderlyingthreadcanbeusedbyanothergo-routine.Whenago-routinewakesup,itmightbeonadifferentthread.Gohandlesallthisbehindthescenes.--Butforallintentsandpurposesyouwouldtreatago-routinelikeathreadwhenitcomestomemoryaccess.However,youdonthavetobeasconservativewhenusinggo-routinesasyoudothreads.**Whenago-routineisblockedbyLock,RLock,achannel,orSleep,theunderlyingthreadmightbere-used.Nocpuisusedbythatgo-routine-thinkofitaswaitinginline.Likeotherlanguagesaninfinitelooplikefor{}wouldblockwhilekeepingthecpuandgo-routinebusy-thinkofthatasrunningaroundinacircle-youllgetdizzy,throwup,andthepeoplearoundyouwontbeveryhappy.
本文内容总结:原文链接,
原文链接:https://www.cnblogs.com/alin-qu/p/10632555.html