123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
- <library id="fiber" name="Fiber" dirname="fiber" last-revision="$Date: 2018/10/22 08:13:04 $"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <libraryinfo>
- <authorgroup>
- <author>
- <firstname>Oliver</firstname> <surname>Kowalke</surname>
- </author>
- </authorgroup>
- <copyright>
- <year>2013</year> <holder>Oliver Kowalke</holder>
- </copyright>
- <legalnotice id="fiber.legal">
- <para>
- Distributed under the Boost Software License, Version 1.0. (See accompanying
- file LICENSE_1_0.txt or copy at <ulink url="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</ulink>)
- </para>
- </legalnotice>
- <librarypurpose>
- C++ Library to cooperatively schedule and synchronize micro-threads
- </librarypurpose>
- <librarycategory name="category:text"></librarycategory>
- </libraryinfo>
- <title>Fiber</title>
- <section id="fiber.overview">
- <title><link linkend="fiber.overview">Overview</link></title>
- <para>
- <emphasis role="bold">Boost.Fiber</emphasis> provides a framework for micro-/userland-threads
- (fibers) scheduled cooperatively. The API contains classes and functions to
- manage and synchronize fibers similiarly to <ulink url="http://en.cppreference.com/w/cpp/thread">standard
- thread support library</ulink>.
- </para>
- <para>
- Each fiber has its own stack.
- </para>
- <para>
- A fiber can save the current execution state, including all registers and CPU
- flags, the instruction pointer, and the stack pointer and later restore this
- state. The idea is to have multiple execution paths running on a single thread
- using cooperative scheduling (versus threads, which are preemptively scheduled).
- The running fiber decides explicitly when it should yield to allow another
- fiber to run (context switching). <emphasis role="bold">Boost.Fiber</emphasis>
- internally uses <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/cc.html"><emphasis>call/cc</emphasis></ulink>
- from <ulink url="http://www.boost.org/doc/libs/release/libs/context/index.html">Boost.Context</ulink>;
- the classes in this library manage, schedule and, when needed, synchronize
- those execution contexts. A context switch between threads usually costs thousands
- of CPU cycles on x86, compared to a fiber switch with less than a hundred cycles.
- A fiber runs on a single thread at any point in time.
- </para>
- <para>
- In order to use the classes and functions described here, you can either include
- the specific headers specified by the descriptions of each class or function,
- or include the master library header:
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">all</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- </programlisting>
- <para>
- which includes all the other headers in turn.
- </para>
- <para>
- The namespaces used are:
- </para>
- <programlisting><phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">this_fiber</phrase>
- </programlisting>
- <bridgehead renderas="sect3" id="fiber.overview.h0">
- <phrase id="fiber.overview.fibers_and_threads"/><link linkend="fiber.overview.fibers_and_threads">Fibers
- and Threads</link>
- </bridgehead>
- <para>
- Control is cooperatively passed between fibers launched on a given thread.
- At a given moment, on a given thread, at most one fiber is running.
- </para>
- <para>
- Spawning additional fibers on a given thread does not distribute your program
- across more hardware cores, though it can make more effective use of the core
- on which it's running.
- </para>
- <para>
- On the other hand, a fiber may safely access any resource exclusively owned
- by its parent thread without explicitly needing to defend that resource against
- concurrent access by other fibers on the same thread. You are already guaranteed
- that no other fiber on that thread is concurrently touching that resource.
- This can be particularly important when introducing concurrency in legacy code.
- You can safely spawn fibers running old code, using asynchronous I/O to interleave
- execution.
- </para>
- <para>
- In effect, fibers provide a natural way to organize concurrent code based on
- asynchronous I/O. Instead of chaining together completion handlers, code running
- on a fiber can make what looks like a normal blocking function call. That call
- can cheaply suspend the calling fiber, allowing other fibers on the same thread
- to run. When the operation has completed, the suspended fiber resumes, without
- having to explicitly save or restore its state. Its local stack variables persist
- across the call.
- </para>
- <para>
- A fiber can be migrated from one thread to another, though the library does
- not do this by default. It is possible for you to supply a custom scheduler
- that migrates fibers between threads. You may specify custom fiber properties
- to help your scheduler decide which fibers are permitted to migrate. Please
- see <link linkend="migration">Migrating fibers between threads</link> and
- <link linkend="custom">Customization</link> for more details.
- </para>
- <para>
- <emphasis role="bold">Boost.Fiber</emphasis> allows to <emphasis role="bold"><code><phrase
- role="identifier">multiplex</phrase> <phrase role="identifier">fibers</phrase>
- <phrase role="identifier">across</phrase> <phrase role="identifier">multiple</phrase>
- <phrase role="identifier">cores</phrase></code></emphasis> (see <link linkend="class_numa_work_stealing"><code>numa::work_stealing</code></link>).
- </para>
- <para>
- A fiber launched on a particular thread continues running on that thread unless
- migrated. It might be unblocked (see <link linkend="blocking">Blocking</link>
- below) by some other thread, but that only transitions the fiber from <quote>blocked</quote>
- to <quote>ready</quote> on its current thread — it does not cause the fiber to
- resume on the thread that unblocked it.
- </para>
- <anchor id="thread_local_storage"/>
- <bridgehead renderas="sect3" id="fiber.overview.h1">
- <phrase id="fiber.overview.thread_local_storage"/><link linkend="fiber.overview.thread_local_storage">thread-local
- storage</link>
- </bridgehead>
- <para>
- Unless migrated, a fiber may access thread-local storage; however that storage
- will be shared among all fibers running on the same thread. For fiber-local
- storage, please see <link linkend="class_fiber_specific_ptr"><code>fiber_specific_ptr</code></link>.
- </para>
- <anchor id="cross_thread_sync"/>
- <bridgehead renderas="sect3" id="fiber.overview.h2">
- <phrase id="fiber.overview.boost_fibers_no_atomics"/><link linkend="fiber.overview.boost_fibers_no_atomics">BOOST_FIBERS_NO_ATOMICS</link>
- </bridgehead>
- <para>
- The fiber synchronization objects provided by this library will, by default,
- safely synchronize fibers running on different threads. However, this level
- of synchronization can be removed (for performance) by building the library
- with <emphasis role="bold"><code><phrase role="identifier">BOOST_FIBERS_NO_ATOMICS</phrase></code></emphasis>
- defined. When the library is built with that macro, you must ensure that all
- the fibers referencing a particular synchronization object are running in the
- same thread. Please see <link linkend="synchronization">Synchronization</link>.
- </para>
- <anchor id="blocking"/>
- <bridgehead renderas="sect3" id="fiber.overview.h3">
- <phrase id="fiber.overview.blocking"/><link linkend="fiber.overview.blocking">Blocking</link>
- </bridgehead>
- <para>
- Normally, when this documentation states that a particular fiber <emphasis>blocks</emphasis>
- (or equivalently, <emphasis>suspends),</emphasis> it means that it yields control,
- allowing other fibers on the same thread to run. The synchronization mechanisms
- provided by <emphasis role="bold">Boost.Fiber</emphasis> have this behavior.
- </para>
- <para>
- A fiber may, of course, use normal thread synchronization mechanisms; however
- a fiber that invokes any of these mechanisms will block its entire thread,
- preventing any other fiber from running on that thread in the meantime. For
- instance, when a fiber wants to wait for a value from another fiber in the
- same thread, using <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">future</phrase></code> would be unfortunate: <code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase
- role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special">()</phrase></code>
- would block the whole thread, preventing the other fiber from delivering its
- value. Use <link linkend="class_future"><code>future<></code></link> instead.
- </para>
- <para>
- Similarly, a fiber that invokes a normal blocking I/O operation will block
- its entire thread. Fiber authors are encouraged to consistently use asynchronous
- I/O. <ulink url="http://www.boost.org/doc/libs/release/libs/asio/index.html">Boost.Asio</ulink>
- and other asynchronous I/O operations can straightforwardly be adapted for
- <emphasis role="bold">Boost.Fiber</emphasis>: see <link linkend="callbacks">Integrating
- Fibers with Asynchronous Callbacks</link>.
- </para>
- <para>
- <emphasis role="bold">Boost.Fiber</emphasis> depends upon <ulink url="http://www.boost.org/doc/libs/release/libs/context/index.html">Boost.Context</ulink>.
- Boost version 1.61.0 or greater is required.
- </para>
- <note>
- <para>
- This library requires C++11!
- </para>
- </note>
- <section id="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber">
- <title><anchor id="implementation"/><link linkend="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber">Implementations:
- fcontext_t, ucontext_t and WinFiber</link></title>
- <para>
- <emphasis role="bold">Boost.Fiber</emphasis> uses <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/cc.html"><emphasis>call/cc</emphasis></ulink>
- from <ulink url="http://www.boost.org/doc/libs/release/libs/context/index.html">Boost.Context</ulink>
- as building-block.
- </para>
- <bridgehead renderas="sect4" id="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber.h0">
- <phrase id="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber.fcontext_t"/><link
- linkend="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber.fcontext_t">fcontext_t</link>
- </bridgehead>
- <para>
- The implementation uses <code><phrase role="identifier">fcontext_t</phrase></code>
- per default. fcontext_t is based on assembler and not available for all platforms.
- It provides a much better performance than <code><phrase role="identifier">ucontext_t</phrase></code>
- (the context switch takes two magnitudes of order less CPU cycles; see section
- <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/performance.html"><emphasis>performance</emphasis></ulink>)
- and <code><phrase role="identifier">WinFiber</phrase></code>.
- </para>
- <bridgehead renderas="sect4" id="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber.h1">
- <phrase id="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber.ucontext_t"/><link
- linkend="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber.ucontext_t">ucontext_t</link>
- </bridgehead>
- <para>
- As an alternative, <ulink url="https://en.wikipedia.org/wiki/Setcontext"><code><phrase
- role="identifier">ucontext_t</phrase></code></ulink> can be used by compiling
- with <code><phrase role="identifier">BOOST_USE_UCONTEXT</phrase></code> and
- b2 property <code><phrase role="identifier">context</phrase><phrase role="special">-</phrase><phrase
- role="identifier">impl</phrase><phrase role="special">=</phrase><phrase role="identifier">ucontext</phrase></code>.
- <code><phrase role="identifier">ucontext_t</phrase></code> might be available
- on a broader range of POSIX-platforms but has some <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/rational.html#ucontext"><emphasis>disadvantages</emphasis></ulink>
- (for instance deprecated since POSIX.1-2003, not C99 conform).
- </para>
- <note>
- <para>
- <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/cc.html"><emphasis>call/cc</emphasis></ulink>
- supports <link linkend="segmented"><emphasis>Segmented stacks</emphasis></link>
- only with <code><phrase role="identifier">ucontext_t</phrase></code> as
- its implementation.
- </para>
- </note>
- <bridgehead renderas="sect4" id="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber.h2">
- <phrase id="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber.winfiber"/><link
- linkend="fiber.overview.implementations__fcontext_t__ucontext_t_and_winfiber.winfiber">WinFiber</link>
- </bridgehead>
- <para>
- With <code><phrase role="identifier">BOOST_USE_WINFIB</phrase></code> and
- b2 property <code><phrase role="identifier">context</phrase><phrase role="special">-</phrase><phrase
- role="identifier">impl</phrase><phrase role="special">=</phrase><phrase role="identifier">winfib</phrase></code>
- Win32-Fibers are used as implementation for <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/cc.html"><emphasis>call/cc</emphasis></ulink>.
- </para>
- <para>
- Because the TIB (thread information block) is not fully described in the
- MSDN, it might be possible that not all required TIB-parts are swapped.
- </para>
- <note>
- <para>
- The first call of <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/cc.html"><emphasis>call/cc</emphasis></ulink>
- converts the thread into a Windows fiber by invoking <code><phrase role="identifier">ConvertThreadToFiber</phrase><phrase
- role="special">()</phrase></code>. If desired, <code><phrase role="identifier">ConvertFiberToThread</phrase><phrase
- role="special">()</phrase></code> has to be called by the user explicitly
- in order to release resources allocated by <code><phrase role="identifier">ConvertThreadToFiber</phrase><phrase
- role="special">()</phrase></code> (e.g. after using boost.context).
- </para>
- </note>
- </section>
- <important>
- <para>
- Windows using fcontext_t: turn off global program optimization (/GL) and
- change /EHsc (compiler assumes that functions declared as extern "C"
- never throw a C++ exception) to /EHs (tells compiler assumes that functions
- declared as extern "C" may throw an exception).
- </para>
- </important>
- </section>
- <section id="fiber.fiber_mgmt">
- <title><link linkend="fiber.fiber_mgmt">Fiber management</link></title>
- <bridgehead renderas="sect3" id="fiber.fiber_mgmt.h0">
- <phrase id="fiber.fiber_mgmt.synopsis"/><link linkend="fiber.fiber_mgmt.synopsis">Synopsis</link>
- </bridgehead>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">all</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">fiber</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special"><(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">r</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&</phrase> <phrase role="identifier">r</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">SchedAlgo</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special">(</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">algo</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">struct</phrase> <phrase role="identifier">algorithm</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">struct</phrase> <phrase role="identifier">algorithm_with_properties</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">round_robin</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">shared_round_robin</phrase><phrase role="special">;</phrase>
- <phrase role="special">}}</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">this_fiber</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">id</phrase> <phrase role="identifier">get_id</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">yield</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">sleep_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">sleep_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">rel_time</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">PROPS</phrase> <phrase role="special">&</phrase> <phrase role="identifier">properties</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- <bridgehead renderas="sect3" id="fiber.fiber_mgmt.h1">
- <phrase id="fiber.fiber_mgmt.tutorial"/><link linkend="fiber.fiber_mgmt.tutorial">Tutorial</link>
- </bridgehead>
- <para>
- Each <link linkend="class_fiber"><code>fiber</code></link> represents a micro-thread which will be launched and managed
- cooperatively by a scheduler. Objects of type <link linkend="class_fiber"><code>fiber</code></link> are move-only.
- </para>
- <programlisting><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f1</phrase><phrase role="special">;</phrase> <phrase role="comment">// not-a-fiber</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">f</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f2</phrase><phrase role="special">(</phrase> <phrase role="identifier">some_fn</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">f1</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase> <phrase role="identifier">f2</phrase><phrase role="special">);</phrase> <phrase role="comment">// f2 moved to f1</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- <bridgehead renderas="sect3" id="fiber.fiber_mgmt.h2">
- <phrase id="fiber.fiber_mgmt.launching"/><link linkend="fiber.fiber_mgmt.launching">Launching</link>
- </bridgehead>
- <para>
- A new fiber is launched by passing an object of a callable type that can be
- invoked with no parameters. If the object must not be copied or moved, then
- <emphasis>std::ref</emphasis> can be used to pass in a reference to the function
- object. In this case, the user must ensure that the referenced object outlives
- the newly-created fiber.
- </para>
- <programlisting><phrase role="keyword">struct</phrase> <phrase role="identifier">callable</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">void</phrase> <phrase role="keyword">operator</phrase><phrase role="special">()();</phrase>
- <phrase role="special">};</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">copies_are_safe</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">callable</phrase> <phrase role="identifier">x</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">x</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase> <phrase role="comment">// x is destroyed, but the newly-created fiber has a copy, so this is OK</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">oops</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">callable</phrase> <phrase role="identifier">x</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ref</phrase><phrase role="special">(</phrase> <phrase role="identifier">x</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="special">}</phrase> <phrase role="comment">// x is destroyed, but the newly-created fiber still has a reference</phrase>
- <phrase role="comment">// this leads to undefined behaviour</phrase>
- </programlisting>
- <para>
- The spawned <link linkend="class_fiber"><code>fiber</code></link> does not immediately start running. It is enqueued
- in the list of ready-to-run fibers, and will run when the scheduler gets around
- to it.
- </para>
- <anchor id="exceptions"/>
- <bridgehead renderas="sect3" id="fiber.fiber_mgmt.h3">
- <phrase id="fiber.fiber_mgmt.exceptions"/><link linkend="fiber.fiber_mgmt.exceptions">Exceptions</link>
- </bridgehead>
- <para>
- An exception escaping from the function or callable object passed to the <link linkend="class_fiber"><code>fiber</code></link>
- constructor
- calls <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">terminate</phrase><phrase role="special">()</phrase></code>.
- If you need to know which exception was thrown, use <link linkend="class_future"><code>future<></code></link> or
- <link linkend="class_packaged_task"><code>packaged_task<></code></link>.
- </para>
- <bridgehead renderas="sect3" id="fiber.fiber_mgmt.h4">
- <phrase id="fiber.fiber_mgmt.detaching"/><link linkend="fiber.fiber_mgmt.detaching">Detaching</link>
- </bridgehead>
- <para>
- A <link linkend="class_fiber"><code>fiber</code></link> can be detached by explicitly invoking the <link linkend="fiber_detach"><code>fiber::detach()</code></link> member
- function. After <link linkend="fiber_detach"><code>fiber::detach()</code></link> is called on a fiber object, that
- object represents <emphasis>not-a-fiber</emphasis>. The fiber object may then
- safely be destroyed.
- </para>
- <programlisting><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">some_fn</phrase><phrase role="special">).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
- </programlisting>
- <para>
- <emphasis role="bold">Boost.Fiber</emphasis> provides a number of ways to wait
- for a running fiber to complete. You can coordinate even with a detached fiber
- using a <link linkend="class_mutex"><code>mutex</code></link>, or <link linkend="class_condition_variable"><code>condition_variable</code></link>, or
- any of the other <link linkend="synchronization">synchronization objects</link>
- provided by the library.
- </para>
- <para>
- If a detached fiber is still running when the thread’s main fiber terminates,
- the thread will not shut down.
- </para>
- <bridgehead renderas="sect3" id="fiber.fiber_mgmt.h5">
- <phrase id="fiber.fiber_mgmt.joining"/><link linkend="fiber.fiber_mgmt.joining">Joining</link>
- </bridgehead>
- <para>
- In order to wait for a fiber to finish, the <link linkend="fiber_join"><code>fiber::join()</code></link> member function
- of the <link linkend="class_fiber"><code>fiber</code></link> object can be used. <link linkend="fiber_join"><code>fiber::join()</code></link> will block
- until the <link linkend="class_fiber"><code>fiber</code></link> object has completed.
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">some_fn</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
- <phrase role="special">...</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f</phrase><phrase role="special">(</phrase> <phrase role="identifier">some_fn</phrase><phrase role="special">);</phrase>
- <phrase role="special">...</phrase>
- <phrase role="identifier">f</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
- </programlisting>
- <para>
- If the fiber has already completed, then <link linkend="fiber_join"><code>fiber::join()</code></link> returns immediately
- and the joined <link linkend="class_fiber"><code>fiber</code></link> object becomes <emphasis>not-a-fiber</emphasis>.
- </para>
- <bridgehead renderas="sect3" id="fiber.fiber_mgmt.h6">
- <phrase id="fiber.fiber_mgmt.destruction"/><link linkend="fiber.fiber_mgmt.destruction">Destruction</link>
- </bridgehead>
- <para>
- When a <link linkend="class_fiber"><code>fiber</code></link> object representing a valid execution context (the fiber
- is <link linkend="fiber_joinable"><code>fiber::joinable()</code></link>) is destroyed, the program terminates. If
- you intend the fiber to outlive the <link linkend="class_fiber"><code>fiber</code></link> object that launched it,
- use the <link linkend="fiber_detach"><code>fiber::detach()</code></link> method.
- </para>
- <programlisting><phrase role="special">{</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f</phrase><phrase role="special">(</phrase> <phrase role="identifier">some_fn</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase> <phrase role="comment">// std::terminate() will be called</phrase>
- <phrase role="special">{</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f</phrase><phrase role="special">(</phrase><phrase role="identifier">some_fn</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">f</phrase><phrase role="special">.</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase> <phrase role="comment">// okay, program continues</phrase>
- </programlisting>
- <anchor id="class_fiber_id"/>
- <bridgehead renderas="sect3" id="fiber.fiber_mgmt.h7">
- <phrase id="fiber.fiber_mgmt.fiber_ids"/><link linkend="fiber.fiber_mgmt.fiber_ids">Fiber
- IDs</link>
- </bridgehead>
- <para>
- Objects of class <link linkend="class_fiber_id"><code><phrase role="identifier">fiber</phrase><phrase
- role="special">::</phrase><phrase role="identifier">id</phrase></code></link> can be
- used to identify fibers. Each running <link linkend="class_fiber"><code>fiber</code></link> has a unique <link linkend="class_fiber_id"><code><phrase
- role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">id</phrase></code></link> obtainable
- from the corresponding <link linkend="class_fiber"><code>fiber</code></link>
- by calling the <link linkend="fiber_get_id"><code>fiber::get_id()</code></link> member
- function. Objects of class <link linkend="class_fiber_id"><code><phrase role="identifier">fiber</phrase><phrase
- role="special">::</phrase><phrase role="identifier">id</phrase></code></link> can be
- copied, and used as keys in associative containers: the full range of comparison
- operators is provided. They can also be written to an output stream using the
- stream insertion operator, though the output format is unspecified.
- </para>
- <para>
- Each instance of <link linkend="class_fiber_id"><code><phrase role="identifier">fiber</phrase><phrase
- role="special">::</phrase><phrase role="identifier">id</phrase></code></link> either
- refers to some fiber, or <emphasis>not-a-fiber</emphasis>. Instances that refer
- to <emphasis>not-a-fiber</emphasis> compare equal to each other, but not equal
- to any instances that refer to an actual fiber. The comparison operators on
- <link linkend="class_fiber_id"><code><phrase role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase
- role="identifier">id</phrase></code></link> yield a total order for every non-equal
- <link linkend="class_fiber_id"><code><phrase role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase
- role="identifier">id</phrase></code></link>.
- </para>
- <anchor id="class_launch"/>
- <bridgehead renderas="sect3" id="fiber.fiber_mgmt.h8">
- <phrase id="fiber.fiber_mgmt.enumeration__code__phrase_role__identifier__launch__phrase___code_"/><link
- linkend="fiber.fiber_mgmt.enumeration__code__phrase_role__identifier__launch__phrase___code_">Enumeration
- <code><phrase role="identifier">launch</phrase></code></link>
- </bridgehead>
- <para>
- <code><phrase role="identifier">launch</phrase></code> specifies whether control
- passes immediately into a newly-launched fiber.
- </para>
- <programlisting><phrase role="keyword">enum</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">launch</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">dispatch</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">post</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- <bridgehead renderas="sect3" id="fiber.fiber_mgmt.h9">
- <phrase id="fiber.fiber_mgmt._code__phrase_role__identifier__dispatch__phrase___code_"/><link
- linkend="fiber.fiber_mgmt._code__phrase_role__identifier__dispatch__phrase___code_"><code><phrase
- role="identifier">dispatch</phrase></code></link>
- </bridgehead>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- A fiber launched with <code><phrase role="identifier">launch</phrase>
- <phrase role="special">==</phrase> <phrase role="identifier">dispatch</phrase></code>
- is entered immediately. In other words, launching a fiber with <code><phrase
- role="identifier">dispatch</phrase></code> suspends the caller (the previously-running
- fiber) until the fiber scheduler has a chance to resume it later.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect3" id="fiber.fiber_mgmt.h10">
- <phrase id="fiber.fiber_mgmt._code__phrase_role__identifier__post__phrase___code_"/><link
- linkend="fiber.fiber_mgmt._code__phrase_role__identifier__post__phrase___code_"><code><phrase
- role="identifier">post</phrase></code></link>
- </bridgehead>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- A fiber launched with <code><phrase role="identifier">launch</phrase>
- <phrase role="special">==</phrase> <phrase role="identifier">post</phrase></code>
- is passed to the fiber scheduler as ready, but it is not yet entered.
- The caller (the previously-running fiber) continues executing. The newly-launched
- fiber will be entered when the fiber scheduler has a chance to resume
- it later.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- If <code><phrase role="identifier">launch</phrase></code> is not explicitly
- specified, <code><phrase role="identifier">post</phrase></code> is the
- default.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <section id="fiber.fiber_mgmt.fiber">
- <title><anchor id="class_fiber"/><link linkend="fiber.fiber_mgmt.fiber">Class
- <code><phrase role="identifier">fiber</phrase></code></link></title>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">id</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">constexpr</phrase> <phrase role="identifier">fiber</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <link linkend="class_launch"><code><phrase role="identifier">launch</phrase></code></link><phrase role="special">,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <phrase role="identifier">StackAllocator</phrase> <phrase role="special">&&,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <link linkend="class_launch"><code><phrase role="identifier">launch</phrase></code></link><phrase role="special">,</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <phrase role="identifier">StackAllocator</phrase> <phrase role="special">&&,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...);</phrase>
- <phrase role="special">~</phrase><phrase role="identifier">fiber</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">fiber</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">fiber</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">joinable</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">id</phrase> <phrase role="identifier">get_id</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">join</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">PROPS</phrase> <phrase role="special">&</phrase> <phrase role="identifier">properties</phrase><phrase role="special">();</phrase>
- <phrase role="special">};</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special"><(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&,</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&,</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">SchedAlgo</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special">(</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <bridgehead renderas="sect4" id="fiber.fiber_mgmt.fiber.h0">
- <phrase id="fiber.fiber_mgmt.fiber.default_constructor"/><link linkend="fiber.fiber_mgmt.fiber.default_constructor">Default
- constructor</link>
- </bridgehead>
- <programlisting><phrase role="keyword">constexpr</phrase> <phrase role="identifier">fiber</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Constructs a <link linkend="class_fiber"><code>fiber</code></link> instance that refers to <emphasis>not-a-fiber</emphasis>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postconditions:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase>
- <phrase role="special">==</phrase> <phrase role="identifier">fiber</phrase><phrase
- role="special">::</phrase><phrase role="identifier">id</phrase><phrase
- role="special">()</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <anchor id="fiber_fiber"/>
- <bridgehead renderas="sect4" id="fiber.fiber_mgmt.fiber.h1">
- <phrase id="fiber.fiber_mgmt.fiber.constructor"/><link linkend="fiber.fiber_mgmt.fiber.constructor">Constructor</link>
- </bridgehead>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <link linkend="class_launch"><code><phrase role="identifier">launch</phrase></code></link> <phrase role="identifier">policy</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <phrase role="identifier">StackAllocator</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">salloc</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <link linkend="class_launch"><code><phrase role="identifier">launch</phrase></code></link> <phrase role="identifier">policy</phrase><phrase role="special">,</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <phrase role="identifier">StackAllocator</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">salloc</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Preconditions:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">Fn</phrase></code> must be copyable
- or movable.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">fn</phrase></code> is copied or moved
- into internal storage for access by the new fiber. If <link linkend="class_launch"><code>launch</code></link> is
- specified (or defaulted) to <code><phrase role="identifier">post</phrase></code>,
- the new fiber is marked <quote>ready</quote> and will be entered at
- the next opportunity. If <code><phrase role="identifier">launch</phrase></code>
- is specified as <code><phrase role="identifier">dispatch</phrase></code>,
- the calling fiber is suspended and the new fiber is entered immediately.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postconditions:</term>
- <listitem>
- <para>
- <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- refers to the newly created fiber of execution.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">fiber_error</phrase></code> if an error
- occurs.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- <link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link>
- is required to allocate a stack for the internal __econtext__. If
- <code><phrase role="identifier">StackAllocator</phrase></code> is not
- explicitly passed, the default stack allocator depends on <code><phrase
- role="identifier">BOOST_USE_SEGMENTED_STACKS</phrase></code>: if defined,
- you will get a <link linkend="class_segmented_stack"><code>segmented_stack</code></link>, else a <link linkend="class_fixedsize_stack"><code>fixedsize_stack</code></link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>See also:</term>
- <listitem>
- <para>
- <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">allocator_arg_t</phrase></code></ulink>, <link linkend="stack">Stack
- allocation</link>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect4" id="fiber.fiber_mgmt.fiber.h2">
- <phrase id="fiber.fiber_mgmt.fiber.move_constructor"/><link linkend="fiber.fiber_mgmt.fiber.move_constructor">Move
- constructor</link>
- </bridgehead>
- <programlisting><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Transfers ownership of the fiber managed by <code><phrase role="identifier">other</phrase></code>
- to the newly constructed <link linkend="class_fiber"><code>fiber</code></link> instance.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postconditions:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">other</phrase><phrase role="special">.</phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase>
- <phrase role="special">==</phrase> <phrase role="identifier">fiber</phrase><phrase
- role="special">::</phrase><phrase role="identifier">id</phrase><phrase
- role="special">()</phrase></code> and <code><phrase role="identifier">get_id</phrase><phrase
- role="special">()</phrase></code> returns the value of <code><phrase
- role="identifier">other</phrase><phrase role="special">.</phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
- prior to the construction
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect4" id="fiber.fiber_mgmt.fiber.h3">
- <phrase id="fiber.fiber_mgmt.fiber.move_assignment_operator"/><link linkend="fiber.fiber_mgmt.fiber.move_assignment_operator">Move
- assignment operator</link>
- </bridgehead>
- <programlisting><phrase role="identifier">fiber</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Transfers ownership of the fiber managed by <code><phrase role="identifier">other</phrase></code>
- (if any) to <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postconditions:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">other</phrase><phrase role="special">-></phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase>
- <phrase role="special">==</phrase> <phrase role="identifier">fiber</phrase><phrase
- role="special">::</phrase><phrase role="identifier">id</phrase><phrase
- role="special">()</phrase></code> and <code><phrase role="identifier">get_id</phrase><phrase
- role="special">()</phrase></code> returns the value of <code><phrase
- role="identifier">other</phrase><phrase role="special">.</phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
- prior to the assignment.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect4" id="fiber.fiber_mgmt.fiber.h4">
- <phrase id="fiber.fiber_mgmt.fiber.destructor"/><link linkend="fiber.fiber_mgmt.fiber.destructor">Destructor</link>
- </bridgehead>
- <programlisting><phrase role="special">~</phrase><phrase role="identifier">fiber</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- If the fiber is <link linkend="fiber_joinable"><code>fiber::joinable()</code></link>, calls std::terminate.
- Destroys <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- The programmer must ensure that the destructor is never executed while
- the fiber is still <link linkend="fiber_joinable"><code>fiber::joinable()</code></link>. Even if you know
- that the fiber has completed, you must still call either <link linkend="fiber_join"><code>fiber::join()</code></link> or
- <link linkend="fiber_detach"><code>fiber::detach()</code></link> before destroying the <code><phrase role="identifier">fiber</phrase></code>
- object.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="fiber_joinable_bridgehead">
- <phrase id="fiber_joinable"/>
- <link linkend="fiber_joinable">Member function <code>joinable</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">joinable</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if <code><phrase
- role="special">*</phrase><phrase role="keyword">this</phrase></code>
- refers to a fiber of execution, which may or may not have completed;
- otherwise <code><phrase role="keyword">false</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="fiber_join_bridgehead">
- <phrase id="fiber_join"/>
- <link linkend="fiber_join">Member function <code>join</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">join</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Preconditions:</term>
- <listitem>
- <para>
- the fiber is <link linkend="fiber_joinable"><code>fiber::joinable()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Waits for the referenced fiber of execution to complete.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postconditions:</term>
- <listitem>
- <para>
- The fiber of execution referenced on entry has completed. <code><phrase
- role="special">*</phrase><phrase role="keyword">this</phrase></code>
- no longer refers to any fiber of execution.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">fiber_error</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Error Conditions:</term>
- <listitem>
- <para>
- <emphasis role="bold">resource_deadlock_would_occur</emphasis>: if
- <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase>
- <phrase role="special">==</phrase> <phrase role="identifier">boost</phrase><phrase
- role="special">::</phrase><phrase role="identifier">this_fiber</phrase><phrase
- role="special">::</phrase><phrase role="identifier">get_id</phrase><phrase
- role="special">()</phrase></code>. <emphasis role="bold">invalid_argument</emphasis>:
- if the fiber is not <link linkend="fiber_joinable"><code>fiber::joinable()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="fiber_detach_bridgehead">
- <phrase id="fiber_detach"/>
- <link linkend="fiber_detach">Member function <code>detach</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Preconditions:</term>
- <listitem>
- <para>
- the fiber is <link linkend="fiber_joinable"><code>fiber::joinable()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- The fiber of execution becomes detached, and no longer has an associated
- <link linkend="class_fiber"><code>fiber</code></link> object.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postconditions:</term>
- <listitem>
- <para>
- <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- no longer refers to any fiber of execution.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">fiber_error</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Error Conditions:</term>
- <listitem>
- <para>
- <emphasis role="bold">invalid_argument</emphasis>: if the fiber is
- not <link linkend="fiber_joinable"><code>fiber::joinable()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="fiber_get_id_bridgehead">
- <phrase id="fiber_get_id"/>
- <link linkend="fiber_get_id">Member function <code>get_id</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">id</phrase> <phrase role="identifier">get_id</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- If <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- refers to a fiber of execution, an instance of <link linkend="class_fiber_id"><code><phrase
- role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase
- role="identifier">id</phrase></code></link> that represents that fiber. Otherwise
- returns a default-constructed <link linkend="class_fiber_id"><code><phrase role="identifier">fiber</phrase><phrase
- role="special">::</phrase><phrase role="identifier">id</phrase></code></link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>See also:</term>
- <listitem>
- <para>
- <link linkend="this_fiber_get_id"><code>this_fiber::get_id()</code></link>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="fiber_properties_bridgehead">
- <phrase id="fiber_properties"/>
- <link linkend="fiber_properties">Templated member
- function <code>properties</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">PROPS</phrase> <phrase role="special">&</phrase> <phrase role="identifier">properties</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Preconditions:</term>
- <listitem>
- <para>
- <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- refers to a fiber of execution. <link linkend="use_scheduling_algorithm"><code>use_scheduling_algorithm()</code></link> has
- been called from this thread with a subclass of <link linkend="class_algorithm_with_properties"><code>algorithm_with_properties<></code></link> with
- the same template argument <code><phrase role="identifier">PROPS</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- a reference to the scheduler properties instance for <code><phrase
- role="special">*</phrase><phrase role="keyword">this</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">bad_cast</phrase></code> if <code><phrase role="identifier">use_scheduling_algorithm</phrase><phrase
- role="special">()</phrase></code> was called with a <code><phrase role="identifier">algorithm_with_properties</phrase></code>
- subclass with some other template parameter than <code><phrase role="identifier">PROPS</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- <link linkend="class_algorithm_with_properties"><code>algorithm_with_properties<></code></link> provides
- a way for a user-coded scheduler to associate extended properties,
- such as priority, with a fiber instance. This method allows access
- to those user-provided properties.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>See also:</term>
- <listitem>
- <para>
- <link linkend="custom">Customization</link>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="fiber_swap_bridgehead">
- <phrase id="fiber_swap"/>
- <link linkend="fiber_swap">Member function <code>swap</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Exchanges the fiber of execution associated with <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code> and <code><phrase role="identifier">other</phrase></code>,
- so <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- becomes associated with the fiber formerly associated with <code><phrase
- role="identifier">other</phrase></code>, and vice-versa.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postconditions:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
- returns the same value as <code><phrase role="identifier">other</phrase><phrase
- role="special">.</phrase><phrase role="identifier">get_id</phrase><phrase
- role="special">()</phrase></code> prior to the call. <code><phrase
- role="identifier">other</phrase><phrase role="special">.</phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
- returns the same value as <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">get_id</phrase><phrase
- role="special">()</phrase></code> prior to the call.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="swap_for_fiber_bridgehead">
- <phrase id="swap_for_fiber"/>
- <link linkend="swap_for_fiber">Non-member function
- <code>swap()</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">fiber</phrase> <phrase role="special">&</phrase> <phrase role="identifier">r</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Same as <code><phrase role="identifier">l</phrase><phrase role="special">.</phrase><phrase
- role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase
- role="identifier">r</phrase><phrase role="special">)</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="operator<_bridgehead">
- <phrase id="operator<"/>
- <link linkend="operator<">Non-member function <code>operator<()</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special"><(</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">fiber</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">r</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if <code><phrase
- role="identifier">l</phrase><phrase role="special">.</phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase>
- <phrase role="special"><</phrase> <phrase role="identifier">r</phrase><phrase
- role="special">.</phrase><phrase role="identifier">get_id</phrase><phrase
- role="special">()</phrase></code> is <code><phrase role="keyword">true</phrase></code>,
- false otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="use_scheduling_algorithm_bridgehead">
- <phrase id="use_scheduling_algorithm"/>
- <link linkend="use_scheduling_algorithm">Non-member
- function <code>use_scheduling_algorithm()</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">SchedAlgo</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special">(</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Directs <emphasis role="bold">Boost.Fiber</emphasis> to use <code><phrase
- role="identifier">SchedAlgo</phrase></code>, which must be a concrete
- subclass of <link linkend="class_algorithm"><code>algorithm</code></link>, as the scheduling algorithm for
- all fibers in the current thread. Pass any required <code><phrase role="identifier">SchedAlgo</phrase></code>
- constructor arguments as <code><phrase role="identifier">args</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- If you want a given thread to use a non-default scheduling algorithm,
- make that thread call <code><phrase role="identifier">use_scheduling_algorithm</phrase><phrase
- role="special">()</phrase></code> before any other <emphasis role="bold">Boost.Fiber</emphasis>
- entry point. If no scheduler has been set for the current thread by
- the time <emphasis role="bold">Boost.Fiber</emphasis> needs to use
- it, the library will create a default <link linkend="class_round_robin"><code>round_robin</code></link> instance
- for this thread.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>See also:</term>
- <listitem>
- <para>
- <link linkend="scheduling">Scheduling</link>, <link linkend="custom">Customization</link>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="has_ready_fibers_bridgehead">
- <phrase id="has_ready_fibers"/>
- <link linkend="has_ready_fibers">Non-member function
- <code>has_ready_fibers()</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if scheduler has
- fibers ready to run.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- Can be used for work-stealing to find an idle scheduler.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section id="fiber.fiber_mgmt.id">
- <title><anchor id="class_id"/><link linkend="fiber.fiber_mgmt.id">Class fiber::id</link></title>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">id</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="keyword">constexpr</phrase> <phrase role="identifier">id</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">==(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">!=(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special"><(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">>(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special"><=(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">>=(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">charT</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">traitsT</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">friend</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">basic_ostream</phrase><phrase role="special"><</phrase> <phrase role="identifier">charT</phrase><phrase role="special">,</phrase> <phrase role="identifier">traitsT</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase>
- <phrase role="keyword">operator</phrase><phrase role="special"><<(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">basic_ostream</phrase><phrase role="special"><</phrase> <phrase role="identifier">charT</phrase><phrase role="special">,</phrase> <phrase role="identifier">traitsT</phrase> <phrase role="special">></phrase> <phrase role="special">&,</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&);</phrase>
- <phrase role="special">};</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <bridgehead renderas="sect4" id="fiber.fiber_mgmt.id.h0">
- <phrase id="fiber.fiber_mgmt.id.constructor"/><link linkend="fiber.fiber_mgmt.id.constructor">Constructor</link>
- </bridgehead>
- <programlisting><phrase role="keyword">constexpr</phrase> <phrase role="identifier">id</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Represents an instance of <emphasis>not-a-fiber</emphasis>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="id_operator_equal_bridgehead">
- <phrase id="id_operator_equal"/>
- <link linkend="id_operator_equal">Member function
- <code>operator==</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">==(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if <code><phrase
- role="special">*</phrase><phrase role="keyword">this</phrase></code>
- and <code><phrase role="identifier">other</phrase></code> represent
- the same fiber, or both represent <emphasis>not-a-fiber</emphasis>,
- <code><phrase role="keyword">false</phrase></code> otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="id_operator_not_equal_bridgehead">
- <phrase id="id_operator_not_equal"/>
- <link linkend="id_operator_not_equal">Member
- function <code>operator!=</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">!=(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code>! (other == * this)</code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="id_operator_less_bridgehead">
- <phrase id="id_operator_less"/>
- <link linkend="id_operator_less">Member function
- <code>operator<</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special"><(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if <code><phrase
- role="special">*</phrase><phrase role="keyword">this</phrase> <phrase
- role="special">!=</phrase> <phrase role="identifier">other</phrase></code>
- is true and the implementation-defined total order of <code><phrase
- role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase
- role="identifier">id</phrase></code> values places <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code> before <code><phrase role="identifier">other</phrase></code>,
- false otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="id_operator_greater_bridgehead">
- <phrase id="id_operator_greater"/>
- <link linkend="id_operator_greater">Member
- function <code>operator></code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">>(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">other</phrase> <phrase role="special"><</phrase>
- <phrase role="special">*</phrase> <phrase role="keyword">this</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="id_operator_less_equal_bridgehead">
- <phrase id="id_operator_less_equal"/>
- <link linkend="id_operator_less_equal">Member
- function <code>operator<=</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special"><=(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="special">!</phrase> <phrase role="special">(</phrase><phrase
- role="identifier">other</phrase> <phrase role="special"><</phrase>
- <phrase role="special">*</phrase> <phrase role="keyword">this</phrase><phrase
- role="special">)</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="id_operator_greater_equal_bridgehead">
- <phrase id="id_operator_greater_equal"/>
- <link linkend="id_operator_greater_equal">Member
- function <code>operator>=</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special">>=(</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="special">!</phrase> <phrase role="special">(*</phrase>
- <phrase role="keyword">this</phrase> <phrase role="special"><</phrase>
- <phrase role="identifier">other</phrase><phrase role="special">)</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect4" id="fiber.fiber_mgmt.id.h1">
- <phrase id="fiber.fiber_mgmt.id.operator_lt__lt_"/><link linkend="fiber.fiber_mgmt.id.operator_lt__lt_">operator<<</link>
- </bridgehead>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">charT</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">traitsT</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">basic_ostream</phrase><phrase role="special"><</phrase> <phrase role="identifier">charT</phrase><phrase role="special">,</phrase> <phrase role="identifier">traitsT</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase>
- <phrase role="keyword">operator</phrase><phrase role="special"><<(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">basic_ostream</phrase><phrase role="special"><</phrase> <phrase role="identifier">charT</phrase><phrase role="special">,</phrase> <phrase role="identifier">traitsT</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">os</phrase><phrase role="special">,</phrase> <phrase role="identifier">id</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Efects:</term>
- <listitem>
- <para>
- Writes the representation of <code><phrase role="identifier">other</phrase></code>
- to stream <code><phrase role="identifier">os</phrase></code>. The representation
- is unspecified.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">os</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section id="fiber.fiber_mgmt.this_fiber">
- <title><link linkend="fiber.fiber_mgmt.this_fiber">Namespace this_fiber</link></title>
- <para>
- In general, <code><phrase role="identifier">this_fiber</phrase></code> operations
- may be called from the <quote>main</quote> fiber — the fiber on which function
- <code><phrase role="identifier">main</phrase><phrase role="special">()</phrase></code>
- is entered — as well as from an explicitly-launched thread’s thread-function.
- That is, in many respects the main fiber on each thread can be treated like
- an explicitly-launched fiber.
- </para>
- <programlisting><phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">this_fiber</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">id</phrase> <phrase role="identifier">get_id</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">yield</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">sleep_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">sleep_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">PROPS</phrase> <phrase role="special">&</phrase> <phrase role="identifier">properties</phrase><phrase role="special">();</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <para>
- <bridgehead renderas="sect4" id="this_fiber_get_id_bridgehead">
- <phrase id="this_fiber_get_id"/>
- <link linkend="this_fiber_get_id">Non-member
- function <code>this_fiber::get_id()</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">operations</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">id</phrase> <phrase role="identifier">get_id</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- An instance of <link linkend="class_fiber_id"><code><phrase role="identifier">fiber</phrase><phrase
- role="special">::</phrase><phrase role="identifier">id</phrase></code></link> that
- represents the currently executing fiber.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="this_fiber_sleep_until_bridgehead">
- <phrase id="this_fiber_sleep_until"/>
- <link linkend="this_fiber_sleep_until">Non-member
- function <code>this_fiber::sleep_until()</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">operations</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">sleep_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">);</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Suspends the current fiber until the time point specified by <code><phrase
- role="identifier">abs_time</phrase></code> has been reached.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- timeout-related exceptions.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- The current fiber will not resume before <code><phrase role="identifier">abs_time</phrase></code>,
- but there are no guarantees about how soon after <code><phrase role="identifier">abs_time</phrase></code>
- it might resume.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- <quote>timeout-related exceptions</quote> are as defined in the C++
- Standard, section <emphasis role="bold">30.2.4 Timing specifications
- [thread.req.timing]</emphasis>: <quote>A function that takes an argument
- which specifies a timeout will throw if, during its execution, a clock,
- time point, or time duration throws an exception. Such exceptions are
- referred to as <emphasis>timeout-related exceptions.</emphasis></quote>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="this_fiber_sleep_for_bridgehead">
- <phrase id="this_fiber_sleep_for"/>
- <link linkend="this_fiber_sleep_for">Non-member
- function <code>this_fiber::sleep_for()</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">operations</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">sleep_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">rel_time</phrase><phrase role="special">);</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Suspends the current fiber until the time duration specified by <code><phrase
- role="identifier">rel_time</phrase></code> has elapsed.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- timeout-related exceptions.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- The current fiber will not resume before <code><phrase role="identifier">rel_time</phrase></code>
- has elapsed, but there are no guarantees about how soon after that
- it might resume.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="this_fiber_yield_bridgehead">
- <phrase id="this_fiber_yield"/>
- <link linkend="this_fiber_yield">Non-member function
- <code>this_fiber::yield()</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">operations</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">yield</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Relinquishes execution control, allowing other fibers to run.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- A fiber that calls <code><phrase role="identifier">yield</phrase><phrase
- role="special">()</phrase></code> is not suspended: it is immediately
- passed to the scheduler as ready to run.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="this_fiber_properties_bridgehead">
- <phrase id="this_fiber_properties"/>
- <link linkend="this_fiber_properties">Non-member
- function <code>this_fiber::properties()</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">operations</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">PROPS</phrase> <phrase role="special">&</phrase> <phrase role="identifier">properties</phrase><phrase role="special">();</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Preconditions:</term>
- <listitem>
- <para>
- <link linkend="use_scheduling_algorithm"><code>use_scheduling_algorithm()</code></link> has been called from
- this thread with a subclass of <link linkend="class_algorithm_with_properties"><code>algorithm_with_properties<></code></link> with
- the same template argument <code><phrase role="identifier">PROPS</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- a reference to the scheduler properties instance for the currently
- running fiber.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">bad_cast</phrase></code> if <code><phrase role="identifier">use_scheduling_algorithm</phrase><phrase
- role="special">()</phrase></code> was called with an <code><phrase
- role="identifier">algorithm_with_properties</phrase></code> subclass
- with some other template parameter than <code><phrase role="identifier">PROPS</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- <link linkend="class_algorithm_with_properties"><code>algorithm_with_properties<></code></link> provides
- a way for a user-coded scheduler to associate extended properties,
- such as priority, with a fiber instance. This function allows access
- to those user-provided properties.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- The first time this function is called from the main fiber of a thread,
- it may internally yield, permitting other fibers to run.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>See also:</term>
- <listitem>
- <para>
- <link linkend="custom">Customization</link>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- </section>
- <section id="fiber.scheduling">
- <title><anchor id="scheduling"/><link linkend="fiber.scheduling">Scheduling</link></title>
- <para>
- The fibers in a thread are coordinated by a fiber manager. Fibers trade control
- cooperatively, rather than preemptively: the currently-running fiber retains
- control until it invokes some operation that passes control to the manager.
- Each time a fiber suspends (or yields), the fiber manager consults a scheduler
- to determine which fiber will run next.
- </para>
- <para>
- <emphasis role="bold">Boost.Fiber</emphasis> provides the fiber manager, but
- the scheduler is a customization point. (See <link linkend="custom">Customization</link>.)
- </para>
- <para>
- Each thread has its own scheduler. Different threads in a process may use different
- schedulers. By default, <emphasis role="bold">Boost.Fiber</emphasis> implicitly
- instantiates <link linkend="class_round_robin"><code>round_robin</code></link> as the scheduler for each thread.
- </para>
- <para>
- You are explicitly permitted to code your own <link linkend="class_algorithm"><code>algorithm</code></link> subclass.
- For the most part, your <code><phrase role="identifier">algorithm</phrase></code>
- subclass need not defend against cross-thread calls: the fiber manager intercepts
- and defers such calls. Most <code><phrase role="identifier">algorithm</phrase></code>
- methods are only ever directly called from the thread whose fibers it is managing
- — with exceptions as documented below.
- </para>
- <para>
- Your <code><phrase role="identifier">algorithm</phrase></code> subclass is
- engaged on a particular thread by calling <link linkend="use_scheduling_algorithm"><code>use_scheduling_algorithm()</code></link>:
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">thread_fn</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special"><</phrase> <phrase role="identifier">my_fiber_scheduler</phrase> <phrase role="special">>();</phrase>
- <phrase role="special">...</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- <para>
- A scheduler class must implement interface <link linkend="class_algorithm"><code>algorithm</code></link>. <emphasis
- role="bold">Boost.Fiber</emphasis> provides schedulers: <link linkend="class_round_robin"><code>round_robin</code></link>,
- <link linkend="class_work_stealing"><code>work_stealing</code></link>, <link linkend="class_numa_work_stealing"><code>numa::work_stealing</code></link> and
- <link linkend="class_shared_work"><code>shared_work</code></link>.
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">thread_count</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// thread registers itself at work-stealing scheduler</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">algo</phrase><phrase role="special">::</phrase><phrase role="identifier">work_stealing</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">thread_count</phrase><phrase role="special">);</phrase>
- <phrase role="special">...</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// count of logical cpus</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">thread_count</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">::</phrase><phrase role="identifier">hardware_concurrency</phrase><phrase role="special">();</phrase>
- <phrase role="comment">// start worker-threads first</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase> <phrase role="special">></phrase> <phrase role="identifier">threads</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">1</phrase> <phrase role="comment">/* count start-thread */</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special"><</phrase> <phrase role="identifier">thread_count</phrase><phrase role="special">;</phrase> <phrase role="special">++</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// spawn thread</phrase>
- <phrase role="identifier">threads</phrase><phrase role="special">.</phrase><phrase role="identifier">emplace_back</phrase><phrase role="special">(</phrase> <phrase role="identifier">thread</phrase><phrase role="special">,</phrase> <phrase role="identifier">thread_count</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// start-thread registers itself at work-stealing scheduler</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">algo</phrase><phrase role="special">::</phrase><phrase role="identifier">work_stealing</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">thread_count</phrase><phrase role="special">);</phrase>
- <phrase role="special">...</phrase>
- </programlisting>
- <para>
- The example spawns as many threads as <code><phrase role="identifier">std</phrase><phrase
- role="special">::</phrase><phrase role="identifier">thread</phrase><phrase
- role="special">::</phrase><phrase role="identifier">hardware_concurrency</phrase><phrase
- role="special">()</phrase></code> returns. Each thread runs a <link linkend="class_work_stealing"><code>work_stealing</code></link> scheduler.
- Each instance of this scheduler needs to know how many threads run the work-stealing
- scheduler in the program. If the local queue of one thread runs out of ready
- fibers, the thread tries to steal a ready fiber from another thread running
- this scheduler.
- </para>
- <para>
- <bridgehead renderas="sect4" id="class_algorithm_bridgehead">
- <phrase id="class_algorithm"/>
- <link linkend="class_algorithm">Class <code>algorithm</code></link>
- </bridgehead>
- </para>
- <para>
- <code><phrase role="identifier">algorithm</phrase></code> is the abstract base
- class defining the interface that a fiber scheduler must implement.
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">algo</phrase><phrase role="special">/</phrase><phrase role="identifier">algorithm</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">algo</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">struct</phrase> <phrase role="identifier">algorithm</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="special">~</phrase><phrase role="identifier">algorithm</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- <phrase role="special">};</phrase>
- <phrase role="special">}}}</phrase>
- </programlisting>
- <para>
- <bridgehead renderas="sect4" id="algorithm_awakened_bridgehead">
- <phrase id="algorithm_awakened"/>
- <link linkend="algorithm_awakened">Member function
- <code>awakened</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Informs the scheduler that fiber <code><phrase role="identifier">f</phrase></code>
- is ready to run. Fiber <code><phrase role="identifier">f</phrase></code>
- might be newly launched, or it might have been blocked but has just been
- awakened, or it might have called <link linkend="this_fiber_yield"><code>this_fiber::yield()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- This method advises the scheduler to add fiber <code><phrase role="identifier">f</phrase></code>
- to its collection of fibers ready to run. A typical scheduler implementation
- places <code><phrase role="identifier">f</phrase></code> into a queue.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>See also:</term>
- <listitem>
- <para>
- <link linkend="class_round_robin"><code>round_robin</code></link>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="algorithm_pick_next_bridgehead">
- <phrase id="algorithm_pick_next"/>
- <link linkend="algorithm_pick_next">Member
- function <code>pick_next</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- the fiber which is to be resumed next, or <code><phrase role="keyword">nullptr</phrase></code>
- if there is no ready fiber.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- This is where the scheduler actually specifies the fiber which is to
- run next. A typical scheduler implementation chooses the head of the
- ready queue.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>See also:</term>
- <listitem>
- <para>
- <link linkend="class_round_robin"><code>round_robin</code></link>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="algorithm_has_ready_fibers_bridgehead">
- <phrase id="algorithm_has_ready_fibers"/>
- <link linkend="algorithm_has_ready_fibers">Member
- function <code>has_ready_fibers</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if scheduler has fibers
- ready to run.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="algorithm_suspend_until_bridgehead">
- <phrase id="algorithm_suspend_until"/>
- <link linkend="algorithm_suspend_until">Member
- function <code>suspend_until</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Informs the scheduler that no fiber will be ready until time-point <code><phrase
- role="identifier">abs_time</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- This method allows a custom scheduler to yield control to the containing
- environment in whatever way makes sense. The fiber manager is stating
- that <code><phrase role="identifier">suspend_until</phrase><phrase role="special">()</phrase></code>
- need not return until <code><phrase role="identifier">abs_time</phrase></code>
- — or <link linkend="algorithm_notify"><code>algorithm::notify()</code></link> is called — whichever comes first.
- The interaction with <code><phrase role="identifier">notify</phrase><phrase
- role="special">()</phrase></code> means that, for instance, calling
- <ulink url="http://en.cppreference.com/w/cpp/thread/sleep_until"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">this_thread</phrase><phrase role="special">::</phrase><phrase
- role="identifier">sleep_until</phrase><phrase role="special">(</phrase><phrase
- role="identifier">abs_time</phrase><phrase role="special">)</phrase></code></ulink>
- would be too simplistic. <link linkend="round_robin_suspend_until"><code>round_robin::suspend_until()</code></link> uses
- a <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">condition_variable</phrase></code></ulink> to coordinate
- with <link linkend="round_robin_notify"><code>round_robin::notify()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- Given that <code><phrase role="identifier">notify</phrase><phrase role="special">()</phrase></code>
- might be called from another thread, your <code><phrase role="identifier">suspend_until</phrase><phrase
- role="special">()</phrase></code> implementation — like the rest of your
- <code><phrase role="identifier">algorithm</phrase></code> implementation
- — must guard any data it shares with your <code><phrase role="identifier">notify</phrase><phrase
- role="special">()</phrase></code> implementation.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="algorithm_notify_bridgehead">
- <phrase id="algorithm_notify"/>
- <link linkend="algorithm_notify">Member function
- <code>notify</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Requests the scheduler to return from a pending call to <link linkend="algorithm_suspend_until"><code>algorithm::suspend_until()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- Alone among the <code><phrase role="identifier">algorithm</phrase></code>
- methods, <code><phrase role="identifier">notify</phrase><phrase role="special">()</phrase></code>
- may be called from another thread. Your <code><phrase role="identifier">notify</phrase><phrase
- role="special">()</phrase></code> implementation must guard any data
- it shares with the rest of your <code><phrase role="identifier">algorithm</phrase></code>
- implementation.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="class_round_robin_bridgehead">
- <phrase id="class_round_robin"/>
- <link linkend="class_round_robin">Class <code>round_robin</code></link>
- </bridgehead>
- </para>
- <para>
- This class implements <link linkend="class_algorithm"><code>algorithm</code></link>, scheduling fibers in round-robin
- fashion.
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">algo</phrase><phrase role="special">/</phrase><phrase role="identifier">round_robin</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">algo</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">round_robin</phrase> <phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">algorithm</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="special">};</phrase>
- <phrase role="special">}}}</phrase>
- </programlisting>
- <para>
- <bridgehead renderas="sect4" id="round_robin_awakened_bridgehead">
- <phrase id="round_robin_awakened"/>
- <link linkend="round_robin_awakened">Member
- function <code>awakened</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Enqueues fiber <code><phrase role="identifier">f</phrase></code> onto
- a ready queue.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="round_robin_pick_next_bridgehead">
- <phrase id="round_robin_pick_next"/>
- <link linkend="round_robin_pick_next">Member
- function <code>pick_next</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- the fiber at the head of the ready queue, or <code><phrase role="keyword">nullptr</phrase></code>
- if the queue is empty.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- Placing ready fibers onto the tail of a queue, and returning them from
- the head of that queue, shares the thread between ready fibers in round-robin
- fashion.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="round_robin_has_ready_fibers_bridgehead">
- <phrase id="round_robin_has_ready_fibers"/>
- <link linkend="round_robin_has_ready_fibers">Member
- function <code>has_ready_fibers</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if scheduler has fibers
- ready to run.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="round_robin_suspend_until_bridgehead">
- <phrase id="round_robin_suspend_until"/>
- <link linkend="round_robin_suspend_until">Member
- function <code>suspend_until</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Informs <code><phrase role="identifier">round_robin</phrase></code> that
- no ready fiber will be available until time-point <code><phrase role="identifier">abs_time</phrase></code>.
- This implementation blocks in <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable/wait_until"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">condition_variable</phrase><phrase role="special">::</phrase><phrase
- role="identifier">wait_until</phrase><phrase role="special">()</phrase></code></ulink>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="round_robin_notify_bridgehead">
- <phrase id="round_robin_notify"/>
- <link linkend="round_robin_notify">Member function
- <code>notify</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Wake up a pending call to <link linkend="round_robin_suspend_until"><code>round_robin::suspend_until()</code></link>,
- some fibers might be ready. This implementation wakes <code><phrase role="identifier">suspend_until</phrase><phrase
- role="special">()</phrase></code> via <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable/notify_all"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">condition_variable</phrase><phrase role="special">::</phrase><phrase
- role="identifier">notify_all</phrase><phrase role="special">()</phrase></code></ulink>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="class_work_stealing_bridgehead">
- <phrase id="class_work_stealing"/>
- <link linkend="class_work_stealing">Class <code>work_stealing</code></link>
- </bridgehead>
- </para>
- <para>
- This class implements <link linkend="class_algorithm"><code>algorithm</code></link>; if the local ready-queue runs
- out of ready fibers, ready fibers are stolen from other schedulers.<sbr/> The
- victim scheduler (from which a ready fiber is stolen) is selected at random.
- </para>
- <note>
- <para>
- Worker-threads are stored in a static variable, dynamically adding/removing
- worker threads is not supported.
- </para>
- </note>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">algo</phrase><phrase role="special">/</phrase><phrase role="identifier">work_stealing</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">algo</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">algorithm</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">work_stealing</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">thread_count</phrase><phrase role="special">,</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">suspend</phrase> <phrase role="special">=</phrase> <phrase role="keyword">false</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">work_stealing</phrase><phrase role="special">(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">work_stealing</phrase><phrase role="special">(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="special">&&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">work_stealing</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">work_stealing</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="special">&&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="special">};</phrase>
- <phrase role="special">}}}</phrase>
- </programlisting>
- <bridgehead renderas="sect3" id="fiber.scheduling.h0">
- <phrase id="fiber.scheduling.constructor"/><link linkend="fiber.scheduling.constructor">Constructor</link>
- </bridgehead>
- <programlisting><phrase role="identifier">work_stealing</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">thread_count</phrase><phrase role="special">,</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">suspend</phrase> <phrase role="special">=</phrase> <phrase role="keyword">false</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Constructs work-stealing scheduling algorithm. <code><phrase role="identifier">thread_count</phrase></code>
- represents the number of threads running this algorithm.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">system_error</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- If <code><phrase role="identifier">suspend</phrase></code> is set to
- <code><phrase role="keyword">true</phrase></code>, then the scheduler
- suspends if no ready fiber could be stolen. The scheduler will by woken
- up if a sleeping fiber times out or it was notified from remote (other
- thread or fiber scheduler).
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="work_stealing_awakened_bridgehead">
- <phrase id="work_stealing_awakened"/>
- <link linkend="work_stealing_awakened">Member
- function <code>awakened</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Enqueues fiber <code><phrase role="identifier">f</phrase></code> onto
- the shared ready queue.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="work_stealing_pick_next_bridgehead">
- <phrase id="work_stealing_pick_next"/>
- <link linkend="work_stealing_pick_next">Member
- function <code>pick_next</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- the fiber at the head of the ready queue, or <code><phrase role="keyword">nullptr</phrase></code>
- if the queue is empty.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- Placing ready fibers onto the tail of the sahred queue, and returning
- them from the head of that queue, shares the thread between ready fibers
- in round-robin fashion.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="work_stealing_has_ready_fibers_bridgehead">
- <phrase id="work_stealing_has_ready_fibers"/>
- <link linkend="work_stealing_has_ready_fibers">Member
- function <code>has_ready_fibers</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if scheduler has fibers
- ready to run.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="work_stealing_suspend_until_bridgehead">
- <phrase id="work_stealing_suspend_until"/>
- <link linkend="work_stealing_suspend_until">Member
- function <code>suspend_until</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Informs <code><phrase role="identifier">work_stealing</phrase></code>
- that no ready fiber will be available until time-point <code><phrase
- role="identifier">abs_time</phrase></code>. This implementation blocks
- in <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable/wait_until"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">condition_variable</phrase><phrase role="special">::</phrase><phrase
- role="identifier">wait_until</phrase><phrase role="special">()</phrase></code></ulink>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="work_stealing_notify_bridgehead">
- <phrase id="work_stealing_notify"/>
- <link linkend="work_stealing_notify">Member
- function <code>notify</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Wake up a pending call to <link linkend="work_stealing_suspend_until"><code>work_stealing::suspend_until()</code></link>,
- some fibers might be ready. This implementation wakes <code><phrase role="identifier">suspend_until</phrase><phrase
- role="special">()</phrase></code> via <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable/notify_all"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">condition_variable</phrase><phrase role="special">::</phrase><phrase
- role="identifier">notify_all</phrase><phrase role="special">()</phrase></code></ulink>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="class_shared_work_bridgehead">
- <phrase id="class_shared_work"/>
- <link linkend="class_shared_work">Class <code>shared_work</code></link>
- </bridgehead>
- </para>
- <note>
- <para>
- Because of the non-locality of data, <emphasis>shared_work</emphasis> is
- less performant than <link linkend="class_work_stealing"><code>work_stealing</code></link>.
- </para>
- </note>
- <para>
- This class implements <link linkend="class_algorithm"><code>algorithm</code></link>, scheduling fibers in round-robin
- fashion. Ready fibers are shared between all instances (running on different
- threads) of shared_work, thus the work is distributed equally over all threads.
- </para>
- <note>
- <para>
- Worker-threads are stored in a static variable, dynamically adding/removing
- worker threads is not supported.
- </para>
- </note>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">algo</phrase><phrase role="special">/</phrase><phrase role="identifier">shared_work</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">algo</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">shared_work</phrase> <phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">algorithm</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="special">};</phrase>
- <phrase role="special">}}}</phrase>
- </programlisting>
- <para>
- <bridgehead renderas="sect4" id="shared_work_awakened_bridgehead">
- <phrase id="shared_work_awakened"/>
- <link linkend="shared_work_awakened">Member
- function <code>awakened</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Enqueues fiber <code><phrase role="identifier">f</phrase></code> onto
- the shared ready queue.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="shared_work_pick_next_bridgehead">
- <phrase id="shared_work_pick_next"/>
- <link linkend="shared_work_pick_next">Member
- function <code>pick_next</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- the fiber at the head of the ready queue, or <code><phrase role="keyword">nullptr</phrase></code>
- if the queue is empty.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- Placing ready fibers onto the tail of the shared queue, and returning
- them from the head of that queue, shares the thread between ready fibers
- in round-robin fashion.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="shared_work_has_ready_fibers_bridgehead">
- <phrase id="shared_work_has_ready_fibers"/>
- <link linkend="shared_work_has_ready_fibers">Member
- function <code>has_ready_fibers</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if scheduler has fibers
- ready to run.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="shared_work_suspend_until_bridgehead">
- <phrase id="shared_work_suspend_until"/>
- <link linkend="shared_work_suspend_until">Member
- function <code>suspend_until</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Informs <code><phrase role="identifier">shared_work</phrase></code> that
- no ready fiber will be available until time-point <code><phrase role="identifier">abs_time</phrase></code>.
- This implementation blocks in <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable/wait_until"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">condition_variable</phrase><phrase role="special">::</phrase><phrase
- role="identifier">wait_until</phrase><phrase role="special">()</phrase></code></ulink>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="shared_work_notify_bridgehead">
- <phrase id="shared_work_notify"/>
- <link linkend="shared_work_notify">Member function
- <code>notify</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Wake up a pending call to <link linkend="shared_work_suspend_until"><code>shared_work::suspend_until()</code></link>,
- some fibers might be ready. This implementation wakes <code><phrase role="identifier">suspend_until</phrase><phrase
- role="special">()</phrase></code> via <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable/notify_all"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">condition_variable</phrase><phrase role="special">::</phrase><phrase
- role="identifier">notify_all</phrase><phrase role="special">()</phrase></code></ulink>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect3" id="fiber.scheduling.h1">
- <phrase id="fiber.scheduling.custom_scheduler_fiber_properties"/><link linkend="fiber.scheduling.custom_scheduler_fiber_properties">Custom
- Scheduler Fiber Properties</link>
- </bridgehead>
- <para>
- A scheduler class directly derived from <link linkend="class_algorithm"><code>algorithm</code></link> can use any
- information available from <link linkend="class_context"><code>context</code></link> to implement the <code><phrase
- role="identifier">algorithm</phrase></code> interface. But a custom scheduler
- might need to track additional properties for a fiber. For instance, a priority-based
- scheduler would need to track a fiber’s priority.
- </para>
- <para>
- <emphasis role="bold">Boost.Fiber</emphasis> provides a mechanism by which
- your custom scheduler can associate custom properties with each fiber.
- </para>
- <para>
- <bridgehead renderas="sect4" id="class_fiber_properties_bridgehead">
- <phrase id="class_fiber_properties"/>
- <link linkend="class_fiber_properties">Class
- <code>fiber_properties</code></link>
- </bridgehead>
- </para>
- <para>
- A custom fiber properties class must be derived from <code><phrase role="identifier">fiber_properties</phrase></code>.
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">properties</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">fiber_properties</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">fiber_properties</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="special">~</phrase><phrase role="identifier">fiber_properties</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">protected</phrase><phrase role="special">:</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="special">};</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <bridgehead renderas="sect3" id="fiber.scheduling.h2">
- <phrase id="fiber.scheduling.constructor0"/><link linkend="fiber.scheduling.constructor0">Constructor</link>
- </bridgehead>
- <programlisting><phrase role="identifier">fiber_properties</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Constructs base-class component of custom subclass.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- Your subclass constructor must accept a <code><phrase role="identifier">context</phrase><phrase
- role="special">*</phrase></code> and pass it to the base-class <code><phrase
- role="identifier">fiber_properties</phrase></code> constructor.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="fiber_properties_notify_bridgehead">
- <phrase id="fiber_properties_notify"/>
- <link linkend="fiber_properties_notify">Member
- function <code>notify</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Pass control to the custom <link linkend="class_algorithm_with_properties"><code>algorithm_with_properties<></code></link> subclass’s
- <link linkend="algorithm_with_properties_property_change"><code>algorithm_with_properties::property_change()</code></link> method.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- A custom scheduler’s <link linkend="algorithm_with_properties_pick_next"><code>algorithm_with_properties::pick_next()</code></link> method
- might dynamically select from the ready fibers, or <link linkend="algorithm_with_properties_awakened"><code>algorithm_with_properties::awakened()</code></link> might
- instead insert each ready fiber into some form of ready queue for <code><phrase
- role="identifier">pick_next</phrase><phrase role="special">()</phrase></code>.
- In the latter case, if application code modifies a fiber property (e.g.
- priority) that should affect that fiber’s relationship to other ready
- fibers, the custom scheduler must be given the opportunity to reorder
- its ready queue. The custom property subclass should implement an access
- method to modify such a property; that access method should call <code><phrase
- role="identifier">notify</phrase><phrase role="special">()</phrase></code>
- once the new property value has been stored. This passes control to the
- custom scheduler’s <code><phrase role="identifier">property_change</phrase><phrase
- role="special">()</phrase></code> method, allowing the custom scheduler
- to reorder its ready queue appropriately. Use at your discretion. Of
- course, if you define a property which does not affect the behavior of
- the <code><phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase></code>
- method, you need not call <code><phrase role="identifier">notify</phrase><phrase
- role="special">()</phrase></code> when that property is modified.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="class_algorithm_with_properties_bridgehead">
- <phrase id="class_algorithm_with_properties"/>
- <link linkend="class_algorithm_with_properties">Template
- <code>algorithm_with_properties<></code></link>
- </bridgehead>
- </para>
- <para>
- A custom scheduler that depends on a custom properties class <code><phrase
- role="identifier">PROPS</phrase></code> should be derived from <code><phrase
- role="identifier">algorithm_with_properties</phrase><phrase role="special"><</phrase><phrase
- role="identifier">PROPS</phrase><phrase role="special">></phrase></code>.
- <code><phrase role="identifier">PROPS</phrase></code> should be derived from
- <link linkend="class_fiber_properties"><code>fiber_properties</code></link>.
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">algorithm</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">algo</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">struct</phrase> <phrase role="identifier">algorithm_with_properties</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*,</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">PROPS</phrase> <phrase role="special">&</phrase> <phrase role="identifier">properties</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">property_change</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*,</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="identifier">fiber_properties</phrase> <phrase role="special">*</phrase> <phrase role="identifier">new_properties</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*);</phrase>
- <phrase role="special">};</phrase>
- <phrase role="special">}}}</phrase>
- </programlisting>
- <para>
- <bridgehead renderas="sect4" id="algorithm_with_properties_awakened_bridgehead">
- <phrase id="algorithm_with_properties_awakened"/>
- <link linkend="algorithm_with_properties_awakened">Member
- function <code>awakened</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">,</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">&</phrase> <phrase role="identifier">properties</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Informs the scheduler that fiber <code><phrase role="identifier">f</phrase></code>
- is ready to run, like <link linkend="algorithm_awakened"><code>algorithm::awakened()</code></link>. Passes
- the fiber’s associated <code><phrase role="identifier">PROPS</phrase></code>
- instance.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- An <code><phrase role="identifier">algorithm_with_properties</phrase><phrase
- role="special"><></phrase></code> subclass must override this method
- instead of <code><phrase role="identifier">algorithm</phrase><phrase
- role="special">::</phrase><phrase role="identifier">awakened</phrase><phrase
- role="special">()</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="algorithm_with_properties_pick_next_bridgehead">
- <phrase id="algorithm_with_properties_pick_next"/>
- <link linkend="algorithm_with_properties_pick_next">Member
- function <code>pick_next</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- the fiber which is to be resumed next, or <code><phrase role="keyword">nullptr</phrase></code>
- if there is no ready fiber.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- same as <link linkend="algorithm_pick_next"><code>algorithm::pick_next()</code></link>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="algorithm_with_properties_has_ready_fibers_bridgehead">
- <phrase id="algorithm_with_properties_has_ready_fibers"/>
- <link linkend="algorithm_with_properties_has_ready_fibers">Member
- function <code>has_ready_fibers</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if scheduler has fibers
- ready to run.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- same as <link linkend="algorithm_has_ready_fibers"><code>algorithm::has_ready_fibers()</code></link>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="algorithm_with_properties_suspend_until_bridgehead">
- <phrase id="algorithm_with_properties_suspend_until"/>
- <link linkend="algorithm_with_properties_suspend_until">Member
- function <code>suspend_until</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Informs the scheduler that no fiber will be ready until time-point <code><phrase
- role="identifier">abs_time</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- same as <link linkend="algorithm_suspend_until"><code>algorithm::suspend_until()</code></link>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="algorithm_with_properties_notify_bridgehead">
- <phrase id="algorithm_with_properties_notify"/>
- <link linkend="algorithm_with_properties_notify">Member
- function <code>notify</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Requests the scheduler to return from a pending call to <link linkend="algorithm_with_properties_suspend_until"><code>algorithm_with_properties::suspend_until()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- same as <link linkend="algorithm_notify"><code>algorithm::notify()</code></link>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="algorithm_with_properties_properties_bridgehead">
- <phrase id="algorithm_with_properties_properties"/>
- <link linkend="algorithm_with_properties_properties">Member
- function <code>properties</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">PROPS</phrase><phrase role="special">&</phrase> <phrase role="identifier">properties</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- the <code><phrase role="identifier">PROPS</phrase></code> instance associated
- with fiber <code><phrase role="identifier">f</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- The fiber’s associated <code><phrase role="identifier">PROPS</phrase></code>
- instance is already passed to <link linkend="algorithm_with_properties_awakened"><code>algorithm_with_properties::awakened()</code></link> and
- <link linkend="algorithm_with_properties_property_change"><code>algorithm_with_properties::property_change()</code></link>.
- However, every <link linkend="class_algorithm"><code>algorithm</code></link> subclass is expected to track
- a collection of ready <link linkend="class_context"><code>context</code></link> instances. This method allows
- your custom scheduler to retrieve the <link linkend="class_fiber_properties"><code>fiber_properties</code></link> subclass
- instance for any <code><phrase role="identifier">context</phrase></code>
- in its collection.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="algorithm_with_properties_property_change_bridgehead">
- <phrase id="algorithm_with_properties_property_change"/>
- <link linkend="algorithm_with_properties_property_change">Member
- function <code>property_change</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">property_change</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">,</phrase> <phrase role="identifier">PROPS</phrase> <phrase role="special">&</phrase> <phrase role="identifier">properties</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Notify the custom scheduler of a possibly-relevant change to a property
- belonging to fiber <code><phrase role="identifier">f</phrase></code>.
- <code><phrase role="identifier">properties</phrase></code> contains the
- new values of all relevant properties.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- This method is only called when a custom <link linkend="class_fiber_properties"><code>fiber_properties</code></link> subclass
- explicitly calls <link linkend="fiber_properties_notify"><code>fiber_properties::notify()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="algorithm_with_properties_new_properties_bridgehead">
- <phrase id="algorithm_with_properties_new_properties"/>
- <link linkend="algorithm_with_properties_new_properties">Member
- function <code>new_properties</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="identifier">fiber_properties</phrase> <phrase role="special">*</phrase> <phrase role="identifier">new_properties</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- A new instance of <link linkend="class_fiber_properties"><code>fiber_properties</code></link> subclass <code><phrase
- role="identifier">PROPS</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- By default, <code><phrase role="identifier">algorithm_with_properties</phrase><phrase
- role="special"><>::</phrase><phrase role="identifier">new_properties</phrase><phrase
- role="special">()</phrase></code> simply returns <code><phrase role="keyword">new</phrase>
- <phrase role="identifier">PROPS</phrase><phrase role="special">(</phrase><phrase
- role="identifier">f</phrase><phrase role="special">)</phrase></code>,
- placing the <code><phrase role="identifier">PROPS</phrase></code> instance
- on the heap. Override this method to allocate <code><phrase role="identifier">PROPS</phrase></code>
- some other way. The returned <code><phrase role="identifier">fiber_properties</phrase></code>
- pointer must point to the <code><phrase role="identifier">PROPS</phrase></code>
- instance to be associated with fiber <code><phrase role="identifier">f</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <anchor id="context"/><bridgehead renderas="sect4" id="class_context_bridgehead">
- <phrase id="class_context"/>
- <link linkend="class_context">Class
- <code>context</code></link>
- </bridgehead>
- </para>
- <para>
- While you are free to treat <code><phrase role="identifier">context</phrase><phrase
- role="special">*</phrase></code> as an opaque token, certain <code><phrase
- role="identifier">context</phrase></code> members may be useful to a custom
- scheduler implementation.
- </para>
- <para>
- <anchor id="ready_queue_t"/>Of particular note is the fact that <code><phrase
- role="identifier">context</phrase></code> contains a hook to participate in
- a <ulink url="http://www.boost.org/doc/libs/release/doc/html/intrusive/list.html"><code><phrase
- role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">intrusive</phrase><phrase
- role="special">::</phrase><phrase role="identifier">list</phrase></code></ulink>
- <literal>typedef</literal>’ed as <code><phrase role="identifier">boost</phrase><phrase
- role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase
- role="special">::</phrase><phrase role="identifier">scheduler</phrase><phrase
- role="special">::</phrase><phrase role="identifier">ready_queue_t</phrase></code>.
- This hook is reserved for use by <link linkend="class_algorithm"><code>algorithm</code></link> implementations. (For
- instance, <link linkend="class_round_robin"><code>round_robin</code></link> contains a <code><phrase role="identifier">ready_queue_t</phrase></code>
- instance to manage its ready fibers.) See <link linkend="context_ready_is_linked"><code>context::ready_is_linked()</code></link>,
- <link linkend="context_ready_link"><code>context::ready_link()</code></link>, <link linkend="context_ready_unlink"><code>context::ready_unlink()</code></link>.
- </para>
- <para>
- Your <code><phrase role="identifier">algorithm</phrase></code> implementation
- may use any container you desire to manage passed <code><phrase role="identifier">context</phrase></code>
- instances. <code><phrase role="identifier">ready_queue_t</phrase></code> avoids
- some of the overhead of typical STL containers.
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">context</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">enum</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">type</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">none</phrase> <phrase role="special">=</phrase> <emphasis>unspecified</emphasis><phrase role="special">,</phrase>
- <phrase role="identifier">main_context</phrase> <phrase role="special">=</phrase> <emphasis>unspecified</emphasis><phrase role="special">,</phrase> <phrase role="comment">// fiber associated with thread's stack</phrase>
- <phrase role="identifier">dispatcher_context</phrase> <phrase role="special">=</phrase> <emphasis>unspecified</emphasis><phrase role="special">,</phrase> <phrase role="comment">// special fiber for maintenance operations</phrase>
- <phrase role="identifier">worker_context</phrase> <phrase role="special">=</phrase> <emphasis>unspecified</emphasis><phrase role="special">,</phrase> <phrase role="comment">// fiber not special to the library</phrase>
- <phrase role="identifier">pinned_context</phrase> <phrase role="special">=</phrase> <emphasis>unspecified</emphasis> <phrase role="comment">// fiber must not be migrated to another thread</phrase>
- <phrase role="special">};</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">context</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">id</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">static</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">active</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">context</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">context</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">context</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">id</phrase> <phrase role="identifier">get_id</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">detach</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">attach</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">is_context</phrase><phrase role="special">(</phrase> <phrase role="identifier">type</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">is_terminated</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">ready_is_linked</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">remote_ready_is_linked</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">wait_is_linked</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">List</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">ready_link</phrase><phrase role="special">(</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">List</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">remote_ready_link</phrase><phrase role="special">(</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">List</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait_link</phrase><phrase role="special">(</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">ready_unlink</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">remote_ready_unlink</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait_unlink</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">suspend</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">schedule</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="special">};</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special"><(</phrase> <phrase role="identifier">context</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">context</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">r</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <para>
- <bridgehead renderas="sect4" id="context_active_bridgehead">
- <phrase id="context_active"/>
- <link linkend="context_active">Static member function
- <code>active</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">static</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">active</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- Pointer to instance of current fiber.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="context_get_id_bridgehead">
- <phrase id="context_get_id"/>
- <link linkend="context_get_id">Member function <code>get_id</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">context</phrase><phrase role="special">::</phrase><phrase role="identifier">id</phrase> <phrase role="identifier">get_id</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- If <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- refers to a fiber of execution, an instance of <link linkend="class_fiber_id"><code><phrase
- role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase
- role="identifier">id</phrase></code></link> that represents that fiber. Otherwise
- returns a default-constructed <link linkend="class_fiber_id"><code><phrase role="identifier">fiber</phrase><phrase
- role="special">::</phrase><phrase role="identifier">id</phrase></code></link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>See also:</term>
- <listitem>
- <para>
- <link linkend="fiber_get_id"><code>fiber::get_id()</code></link>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="context_attach_bridgehead">
- <phrase id="context_attach"/>
- <link linkend="context_attach">Member function <code>attach</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">attach</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">get_scheduler</phrase><phrase role="special">()</phrase>
- <phrase role="special">==</phrase> <phrase role="keyword">nullptr</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Attach fiber <code><phrase role="identifier">f</phrase></code> to scheduler
- running <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postcondition:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">get_scheduler</phrase><phrase role="special">()</phrase>
- <phrase role="special">!=</phrase> <phrase role="keyword">nullptr</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- A typical call: <code><phrase role="identifier">boost</phrase><phrase
- role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase
- role="special">::</phrase><phrase role="identifier">context</phrase><phrase
- role="special">::</phrase><phrase role="identifier">active</phrase><phrase
- role="special">()-></phrase><phrase role="identifier">attach</phrase><phrase
- role="special">(</phrase><phrase role="identifier">f</phrase><phrase
- role="special">);</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">f</phrase></code> must not be the running
- fiber’s context. It must not be <link linkend="blocking"><emphasis>blocked</emphasis></link>
- or terminated. It must not be a <code><phrase role="identifier">pinned_context</phrase></code>.
- It must be currently detached. It must not currently be linked into an
- <link linkend="class_algorithm"><code>algorithm</code></link> implementation’s ready queue. Most of these conditions
- are implied by <code><phrase role="identifier">f</phrase></code> being
- owned by an <code><phrase role="identifier">algorithm</phrase></code>
- implementation: that is, it has been passed to <link linkend="algorithm_awakened"><code>algorithm::awakened()</code></link> but
- has not yet been returned by <link linkend="algorithm_pick_next"><code>algorithm::pick_next()</code></link>.
- Typically a <code><phrase role="identifier">pick_next</phrase><phrase
- role="special">()</phrase></code> implementation would call <code><phrase
- role="identifier">attach</phrase><phrase role="special">()</phrase></code>
- with the <code><phrase role="identifier">context</phrase><phrase role="special">*</phrase></code>
- it is about to return. It must first remove <code><phrase role="identifier">f</phrase></code>
- from its ready queue. You should never pass a <code><phrase role="identifier">pinned_context</phrase></code>
- to <code><phrase role="identifier">attach</phrase><phrase role="special">()</phrase></code>
- because you should never have called its <code><phrase role="identifier">detach</phrase><phrase
- role="special">()</phrase></code> method in the first place.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="context_detach_bridgehead">
- <phrase id="context_detach"/>
- <link linkend="context_detach">Member function <code>detach</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">detach</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- <code><phrase role="special">(</phrase><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">get_scheduler</phrase><phrase
- role="special">()</phrase> <phrase role="special">!=</phrase> <phrase
- role="keyword">nullptr</phrase><phrase role="special">)</phrase> <phrase
- role="special">&&</phrase> <phrase role="special">!</phrase>
- <phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">is_context</phrase><phrase role="special">(</phrase><phrase
- role="identifier">pinned_context</phrase><phrase role="special">)</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Detach fiber <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- from its scheduler running <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postcondition:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">get_scheduler</phrase><phrase role="special">()</phrase>
- <phrase role="special">==</phrase> <phrase role="keyword">nullptr</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- This method must be called on the thread with which the fiber is currently
- associated. <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- must not be the running fiber’s context. It must not be <link linkend="blocking"><emphasis>blocked</emphasis></link>
- or terminated. It must not be a <code><phrase role="identifier">pinned_context</phrase></code>.
- It must not be detached already. It must not already be linked into an
- <link linkend="class_algorithm"><code>algorithm</code></link> implementation’s ready queue. Most of these conditions
- are implied by <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- being passed to <link linkend="algorithm_awakened"><code>algorithm::awakened()</code></link>; an <code><phrase
- role="identifier">awakened</phrase><phrase role="special">()</phrase></code>
- implementation must, however, test for <code><phrase role="identifier">pinned_context</phrase></code>.
- It must call <code><phrase role="identifier">detach</phrase><phrase role="special">()</phrase></code>
- <emphasis>before</emphasis> linking <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code> into its ready queue.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- In particular, it is erroneous to attempt to migrate a fiber from one
- thread to another by calling both <code><phrase role="identifier">detach</phrase><phrase
- role="special">()</phrase></code> and <code><phrase role="identifier">attach</phrase><phrase
- role="special">()</phrase></code> in the <link linkend="algorithm_pick_next"><code>algorithm::pick_next()</code></link> method.
- <code><phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase></code>
- is called on the intended destination thread. <code><phrase role="identifier">detach</phrase><phrase
- role="special">()</phrase></code> must be called on the fiber’s original
- thread. You must call <code><phrase role="identifier">detach</phrase><phrase
- role="special">()</phrase></code> in the corresponding <code><phrase
- role="identifier">awakened</phrase><phrase role="special">()</phrase></code>
- method.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- Unless you intend make a fiber available for potential migration to a
- different thread, you should call neither <code><phrase role="identifier">detach</phrase><phrase
- role="special">()</phrase></code> nor <code><phrase role="identifier">attach</phrase><phrase
- role="special">()</phrase></code> with its <code><phrase role="identifier">context</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="context_is_context_bridgehead">
- <phrase id="context_is_context"/>
- <link linkend="context_is_context">Member function
- <code>is_context</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">is_context</phrase><phrase role="special">(</phrase> <phrase role="identifier">type</phrase> <phrase role="identifier">t</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code> is of the specified type.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">type</phrase><phrase role="special">::</phrase><phrase
- role="identifier">worker_context</phrase></code> here means any fiber
- not special to the library. For <code><phrase role="identifier">type</phrase><phrase
- role="special">::</phrase><phrase role="identifier">main_context</phrase></code>
- the <code><phrase role="identifier">context</phrase></code> is associated
- with the <quote>main</quote> fiber of the thread: the one implicitly
- created by the thread itself, rather than one explicitly created by
- <emphasis role="bold">Boost.Fiber</emphasis>. For <code><phrase role="identifier">type</phrase><phrase
- role="special">::</phrase><phrase role="identifier">dispatcher_context</phrase></code>
- the <code><phrase role="identifier">context</phrase></code> is associated
- with a <quote>dispatching</quote> fiber, responsible for dispatching
- awakened fibers to a scheduler’s ready-queue. The <quote>dispatching</quote>
- fiber is an implementation detail of the fiber manager. The context of
- the <quote>main</quote> or <quote>dispatching</quote> fiber — any fiber
- for which <code><phrase role="identifier">is_context</phrase><phrase
- role="special">(</phrase><phrase role="identifier">pinned_context</phrase><phrase
- role="special">)</phrase></code> is <code><phrase role="keyword">true</phrase></code>
- — must never be passed to <link linkend="context_detach"><code>context::detach()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="context_is_terminated_bridgehead">
- <phrase id="context_is_terminated"/>
- <link linkend="context_is_terminated">Member
- function <code>is_terminated</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">is_terminated</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code> is no longer a valid context.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- The <code><phrase role="identifier">context</phrase></code> has returned
- from its fiber-function and is no longer considered a valid context.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="context_ready_is_linked_bridgehead">
- <phrase id="context_ready_is_linked"/>
- <link linkend="context_ready_is_linked">Member
- function <code>ready_is_linked</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">ready_is_linked</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code> is stored in an <link linkend="class_algorithm"><code>algorithm</code></link>
- implementation’s
- ready-queue.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- Specifically, this method indicates whether <link linkend="context_ready_link"><code>context::ready_link()</code></link> has
- been called on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
- <code><phrase role="identifier">ready_is_linked</phrase><phrase role="special">()</phrase></code>
- has no information about participation in any other containers.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="context_remote_ready_is_linked_bridgehead">
- <phrase id="context_remote_ready_is_linked"/>
- <link linkend="context_remote_ready_is_linked">Member
- function <code>remote_ready_is_linked</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">remote_ready_is_linked</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code> is stored in the fiber manager’s remote-ready-queue.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- A <code><phrase role="identifier">context</phrase></code> signaled as
- ready by another thread is first stored in the fiber manager’s remote-ready-queue.
- This is the mechanism by which the fiber manager protects an <link linkend="class_algorithm"><code>algorithm</code></link> implementation
- from cross-thread <link linkend="algorithm_awakened"><code>algorithm::awakened()</code></link> calls.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="context_wait_is_linked_bridgehead">
- <phrase id="context_wait_is_linked"/>
- <link linkend="context_wait_is_linked">Member
- function <code>wait_is_linked</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">wait_is_linked</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code> is stored in the wait-queue of some
- synchronization object.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- The <code><phrase role="identifier">context</phrase></code> of a fiber
- waiting on a synchronization object (e.g. <code><phrase role="identifier">mutex</phrase></code>,
- <code><phrase role="identifier">condition_variable</phrase></code> etc.)
- is stored in the wait-queue of that synchronization object.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="context_ready_link_bridgehead">
- <phrase id="context_ready_link"/>
- <link linkend="context_ready_link">Member function
- <code>ready_link</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">List</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">ready_link</phrase><phrase role="special">(</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&</phrase> <phrase role="identifier">lst</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Stores <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- in ready-queue <code><phrase role="identifier">lst</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- Argument <code><phrase role="identifier">lst</phrase></code> must be
- a doubly-linked list from <ulink url="http://www.boost.org/doc/libs/release/libs/intrusive/index.html">Boost.Intrusive</ulink>,
- e.g. an instance of <code><phrase role="identifier">boost</phrase><phrase
- role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase
- role="special">::</phrase><phrase role="identifier">scheduler</phrase><phrase
- role="special">::</phrase><phrase role="identifier">ready_queue_t</phrase></code>.
- Specifically, it must be a <ulink url="http://www.boost.org/doc/libs/release/doc/html/intrusive/list.html"><code><phrase
- role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">intrusive</phrase><phrase role="special">::</phrase><phrase
- role="identifier">list</phrase></code></ulink> compatible with the <code><phrase
- role="identifier">list_member_hook</phrase></code> stored in the <code><phrase
- role="identifier">context</phrase></code> object.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="context_remote_ready_link_bridgehead">
- <phrase id="context_remote_ready_link"/>
- <link linkend="context_remote_ready_link">Member
- function <code>remote_ready_link</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">List</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">remote_ready_link</phrase><phrase role="special">(</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&</phrase> <phrase role="identifier">lst</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Stores <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- in remote-ready-queue <code><phrase role="identifier">lst</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- Argument <code><phrase role="identifier">lst</phrase></code> must be
- a doubly-linked list from <ulink url="http://www.boost.org/doc/libs/release/libs/intrusive/index.html">Boost.Intrusive</ulink>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="context_wait_link_bridgehead">
- <phrase id="context_wait_link"/>
- <link linkend="context_wait_link">Member function
- <code>wait_link</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">List</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait_link</phrase><phrase role="special">(</phrase> <phrase role="identifier">List</phrase> <phrase role="special">&</phrase> <phrase role="identifier">lst</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Stores <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- in wait-queue <code><phrase role="identifier">lst</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- Argument <code><phrase role="identifier">lst</phrase></code> must be
- a doubly-linked list from <ulink url="http://www.boost.org/doc/libs/release/libs/intrusive/index.html">Boost.Intrusive</ulink>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="context_ready_unlink_bridgehead">
- <phrase id="context_ready_unlink"/>
- <link linkend="context_ready_unlink">Member
- function <code>ready_unlink</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">ready_unlink</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Removes <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- from ready-queue: undoes the effect of <link linkend="context_ready_link"><code>context::ready_link()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="context_remote_ready_unlink_bridgehead">
- <phrase id="context_remote_ready_unlink"/>
- <link linkend="context_remote_ready_unlink">Member
- function <code>remote_ready_unlink</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">remote_ready_unlink</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Removes <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- from remote-ready-queue.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="context_wait_unlink_bridgehead">
- <phrase id="context_wait_unlink"/>
- <link linkend="context_wait_unlink">Member
- function <code>wait_unlink</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">wait_unlink</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Removes <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- from wait-queue.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="context_suspend_bridgehead">
- <phrase id="context_suspend"/>
- <link linkend="context_suspend">Member function <code>suspend</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">suspend</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Suspends the running fiber (the fiber associated with <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code>) until some other fiber passes <code><phrase
- role="keyword">this</phrase></code> to <link linkend="context_schedule"><code>context::schedule()</code></link>.
- <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- is marked as not-ready, and control passes to the scheduler to select
- another fiber to run.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- This is a low-level API potentially useful for integration with other
- frameworks. It is not intended to be directly invoked by a typical application
- program.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- The burden is on the caller to arrange for a call to <code><phrase role="identifier">schedule</phrase><phrase
- role="special">()</phrase></code> with a pointer to <code><phrase role="keyword">this</phrase></code>
- at some future time.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="context_schedule_bridgehead">
- <phrase id="context_schedule"/>
- <link linkend="context_schedule">Member function
- <code>schedule</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">schedule</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">ctx</phrase> <phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Mark the fiber associated with context <code><phrase role="special">*</phrase><phrase
- role="identifier">ctx</phrase></code> as being ready to run. This does
- not immediately resume that fiber; rather it passes the fiber to the
- scheduler for subsequent resumption. If the scheduler is idle (has not
- returned from a call to <link linkend="algorithm_suspend_until"><code>algorithm::suspend_until()</code></link>),
- <link linkend="algorithm_notify"><code>algorithm::notify()</code></link> is called to wake it up.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- This is a low-level API potentially useful for integration with other
- frameworks. It is not intended to be directly invoked by a typical application
- program.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- It is explicitly supported to call <code><phrase role="identifier">schedule</phrase><phrase
- role="special">(</phrase><phrase role="identifier">ctx</phrase><phrase
- role="special">)</phrase></code> from a thread other than the one on
- which <code><phrase role="special">*</phrase><phrase role="identifier">ctx</phrase></code>
- is currently suspended. The corresponding fiber will be resumed on its
- original thread in due course.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="context_less_bridgehead">
- <phrase id="context_less"/>
- <link linkend="context_less">Non-member function <code>operator<()</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special"><(</phrase> <phrase role="identifier">context</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">context</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">r</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if <code><phrase role="identifier">l</phrase><phrase
- role="special">.</phrase><phrase role="identifier">get_id</phrase><phrase
- role="special">()</phrase> <phrase role="special"><</phrase> <phrase
- role="identifier">r</phrase><phrase role="special">.</phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
- is <code><phrase role="keyword">true</phrase></code>, <code><phrase role="keyword">false</phrase></code>
- otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section id="fiber.stack">
- <title><anchor id="stack"/><link linkend="fiber.stack">Stack allocation</link></title>
- <para>
- A <link linkend="class_fiber"><code>fiber</code></link> uses internally an __econtext__ which manages a set of registers
- and a stack. The memory used by the stack is allocated/deallocated via a <emphasis>stack_allocator</emphasis>
- which is required to model a <link linkend="stack_allocator_concept"><emphasis>stack-allocator
- concept</emphasis></link>.
- </para>
- <para>
- A <emphasis>stack_allocator</emphasis> can be passed to <link linkend="fiber_fiber"><code><phrase
- role="identifier">fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase
- role="special">()</phrase></code></link> or to <link linkend="fibers_async"><code>fibers::async()</code></link>.
- </para>
- <anchor id="stack_allocator_concept"/>
- <bridgehead renderas="sect3" id="fiber.stack.h0">
- <phrase id="fiber.stack.stack_allocator_concept"/><link linkend="fiber.stack.stack_allocator_concept">stack-allocator
- concept</link>
- </bridgehead>
- <para>
- A <emphasis>stack_allocator</emphasis> must satisfy the <emphasis>stack-allocator
- concept</emphasis> requirements shown in the following table, in which <code><phrase
- role="identifier">a</phrase></code> is an object of a <emphasis>stack_allocator</emphasis>
- type, <code><phrase role="identifier">sctx</phrase></code> is a <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/stack/stack_context.html"><code><phrase
- role="identifier">stack_context</phrase></code></ulink>, and <code><phrase
- role="identifier">size</phrase></code> is a <code><phrase role="identifier">std</phrase><phrase
- role="special">::</phrase><phrase role="identifier">size_t</phrase></code>:
- </para>
- <informaltable frame="all">
- <tgroup cols="3">
- <thead>
- <row>
- <entry>
- <para>
- expression
- </para>
- </entry>
- <entry>
- <para>
- return type
- </para>
- </entry>
- <entry>
- <para>
- notes
- </para>
- </entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- <para>
- <code><phrase role="identifier">a</phrase><phrase role="special">(</phrase><phrase
- role="identifier">size</phrase><phrase role="special">)</phrase></code>
- </para>
- </entry>
- <entry>
- </entry>
- <entry>
- <para>
- creates a stack allocator
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- <code><phrase role="identifier">a</phrase><phrase role="special">.</phrase><phrase
- role="identifier">allocate</phrase><phrase role="special">()</phrase></code>
- </para>
- </entry>
- <entry>
- <para>
- <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/stack/stack_context.html"><code><phrase
- role="identifier">stack_context</phrase></code></ulink>
- </para>
- </entry>
- <entry>
- <para>
- creates a stack
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- <code><phrase role="identifier">a</phrase><phrase role="special">.</phrase><phrase
- role="identifier">deallocate</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">sctx</phrase><phrase role="special">)</phrase></code>
- </para>
- </entry>
- <entry>
- <para>
- <code><phrase role="keyword">void</phrase></code>
- </para>
- </entry>
- <entry>
- <para>
- deallocates the stack created by <code><phrase role="identifier">a</phrase><phrase
- role="special">.</phrase><phrase role="identifier">allocate</phrase><phrase
- role="special">()</phrase></code>
- </para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <important>
- <para>
- The implementation of <code><phrase role="identifier">allocate</phrase><phrase
- role="special">()</phrase></code> might include logic to protect against
- exceeding the context's available stack size rather than leaving it as undefined
- behaviour.
- </para>
- </important>
- <important>
- <para>
- Calling <code><phrase role="identifier">deallocate</phrase><phrase role="special">()</phrase></code>
- with a <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/stack/stack_context.html"><code><phrase
- role="identifier">stack_context</phrase></code></ulink> not obtained from
- <code><phrase role="identifier">allocate</phrase><phrase role="special">()</phrase></code>
- results in undefined behaviour.
- </para>
- </important>
- <note>
- <para>
- The memory for the stack is not required to be aligned; alignment takes place
- inside __econtext__.
- </para>
- </note>
- <para>
- See also <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/stack.html">Boost.Context
- stack allocation</ulink>. In particular, <code><phrase role="identifier">traits_type</phrase></code>
- methods are as described for <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/stack/stack_traits.html"><code><phrase
- role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase><phrase
- role="special">::</phrase><phrase role="identifier">stack_traits</phrase></code></ulink>.
- </para>
- <para>
- <bridgehead renderas="sect4" id="class_protected_fixedsize_stack_bridgehead">
- <phrase id="class_protected_fixedsize_stack"/>
- <link linkend="class_protected_fixedsize_stack">Class
- <code>protected_fixedsize_stack</code></link>
- </bridgehead>
- </para>
- <para>
- <emphasis role="bold">Boost.Fiber</emphasis> provides the class <link linkend="class_protected_fixedsize_stack"><code>protected_fixedsize_stack</code></link> which
- models the <link linkend="stack_allocator_concept"><emphasis>stack-allocator
- concept</emphasis></link>. It appends a guard page at the end of each stack
- to protect against exceeding the stack. If the guard page is accessed (read
- or write operation) a segmentation fault/access violation is generated by the
- operating system.
- </para>
- <important>
- <para>
- Using <link linkend="class_protected_fixedsize_stack"><code>protected_fixedsize_stack</code></link> is expensive.
- Launching a new fiber with a stack of this type incurs the overhead of setting
- the memory protection; once allocated, this stack is just as efficient to
- use as <link linkend="class_fixedsize_stack"><code>fixedsize_stack</code></link>.
- </para>
- </important>
- <note>
- <para>
- The appended <code><phrase role="identifier">guard</phrase> <phrase role="identifier">page</phrase></code>
- is <emphasis role="bold">not</emphasis> mapped to physical memory, only virtual
- addresses are used.
- </para>
- </note>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">protected_fixedsize</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">struct</phrase> <phrase role="identifier">protected_fixedsize</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">protected_fixesize</phrase><phrase role="special">(</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">size</phrase> <phrase role="special">=</phrase> <phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase role="identifier">default_size</phrase><phrase role="special">());</phrase>
- <phrase role="identifier">stack_context</phrase> <phrase role="identifier">allocate</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">deallocate</phrase><phrase role="special">(</phrase> <phrase role="identifier">stack_context</phrase> <phrase role="special">&);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <para>
- <bridgehead renderas="sect4" id="protected_fixedsize_allocate_bridgehead">
- <phrase id="protected_fixedsize_allocate"/>
- <link linkend="protected_fixedsize_allocate">Member
- function <code>allocate</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">stack_context</phrase> <phrase role="identifier">allocate</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Preconditions:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
- role="identifier">minimum_size</phrase><phrase role="special">()</phrase>
- <phrase role="special"><=</phrase> <phrase role="identifier">size</phrase></code>
- and <code><phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
- role="identifier">is_unbounded</phrase><phrase role="special">()</phrase>
- <phrase role="special">||</phrase> <phrase role="special">(</phrase>
- <phrase role="identifier">size</phrase> <phrase role="special"><=</phrase>
- <phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
- role="identifier">maximum_size</phrase><phrase role="special">()</phrase>
- <phrase role="special">)</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Allocates memory of at least <code><phrase role="identifier">size</phrase></code>
- bytes and stores a pointer to the stack and its actual size in <code><phrase
- role="identifier">sctx</phrase></code>. Depending on the architecture
- (the stack grows downwards/upwards) the stored address is the highest/lowest
- address of the stack.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="protected_fixesize_deallocate_bridgehead">
- <phrase id="protected_fixesize_deallocate"/>
- <link linkend="protected_fixesize_deallocate">Member
- function <code>deallocate</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">deallocate</phrase><phrase role="special">(</phrase> <phrase role="identifier">stack_context</phrase> <phrase role="special">&</phrase> <phrase role="identifier">sctx</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Preconditions:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
- role="identifier">sp</phrase></code> is valid, <code><phrase role="identifier">traits_type</phrase><phrase
- role="special">::</phrase><phrase role="identifier">minimum_size</phrase><phrase
- role="special">()</phrase> <phrase role="special"><=</phrase> <phrase
- role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
- role="identifier">size</phrase></code> and <code><phrase role="identifier">traits_type</phrase><phrase
- role="special">::</phrase><phrase role="identifier">is_unbounded</phrase><phrase
- role="special">()</phrase> <phrase role="special">||</phrase> <phrase
- role="special">(</phrase> <phrase role="identifier">sctx</phrase><phrase
- role="special">.</phrase><phrase role="identifier">size</phrase> <phrase
- role="special"><=</phrase> <phrase role="identifier">traits_type</phrase><phrase
- role="special">::</phrase><phrase role="identifier">maximum_size</phrase><phrase
- role="special">()</phrase> <phrase role="special">)</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Deallocates the stack space.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="class_pooled_fixedsize_stack_bridgehead">
- <phrase id="class_pooled_fixedsize_stack"/>
- <link linkend="class_pooled_fixedsize_stack">Class
- <code>pooled_fixedsize_stack</code></link>
- </bridgehead>
- </para>
- <para>
- <emphasis role="bold">Boost.Fiber</emphasis> provides the class <link linkend="class_pooled_fixedsize_stack"><code>pooled_fixedsize_stack</code></link> which
- models the <link linkend="stack_allocator_concept"><emphasis>stack-allocator
- concept</emphasis></link>. In contrast to <link linkend="class_protected_fixedsize_stack"><code>protected_fixedsize_stack</code></link> it
- does not append a guard page at the end of each stack. The memory is managed
- internally by <ulink url="http://www.boost.org/doc/libs/release/libs/pool/doc/html/boost/pool.html"><code><phrase
- role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">pool</phrase><phrase
- role="special"><></phrase></code></ulink>.
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">pooled_fixedsize_stack</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">struct</phrase> <phrase role="identifier">pooled_fixedsize_stack</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">pooled_fixedsize_stack</phrase><phrase role="special">(</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">stack_size</phrase> <phrase role="special">=</phrase> <phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase role="identifier">default_size</phrase><phrase role="special">(),</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">next_size</phrase> <phrase role="special">=</phrase> <phrase role="number">32</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">max_size</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">stack_context</phrase> <phrase role="identifier">allocate</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">deallocate</phrase><phrase role="special">(</phrase> <phrase role="identifier">stack_context</phrase> <phrase role="special">&);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <para>
- <bridgehead renderas="sect4" id="pooled_fixedsize_bridgehead">
- <phrase id="pooled_fixedsize"/>
- <link linkend="pooled_fixedsize">Constructor</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">pooled_fixedsize_stack</phrase><phrase role="special">(</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">stack_size</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">next_size</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">max_size</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Preconditions:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
- role="identifier">is_unbounded</phrase><phrase role="special">()</phrase>
- <phrase role="special">||</phrase> <phrase role="special">(</phrase>
- <phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
- role="identifier">maximum_size</phrase><phrase role="special">()</phrase>
- <phrase role="special">>=</phrase> <phrase role="identifier">stack_size</phrase><phrase
- role="special">)</phrase></code> and <code><phrase role="number">0</phrase>
- <phrase role="special"><</phrase> <phrase role="identifier">next_size</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Allocates memory of at least <code><phrase role="identifier">stack_size</phrase></code>
- bytes and stores a pointer to the stack and its actual size in <code><phrase
- role="identifier">sctx</phrase></code>. Depending on the architecture
- (the stack grows downwards/upwards) the stored address is the highest/lowest
- address of the stack. Argument <code><phrase role="identifier">next_size</phrase></code>
- determines the number of stacks to request from the system the first
- time that <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- needs to allocate system memory. The third argument <code><phrase role="identifier">max_size</phrase></code>
- controls how much memory might be allocated for stacks — a value of zero
- means no upper limit.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="pooled_fixedsize_allocate_bridgehead">
- <phrase id="pooled_fixedsize_allocate"/>
- <link linkend="pooled_fixedsize_allocate">Member
- function <code>allocate</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">stack_context</phrase> <phrase role="identifier">allocate</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Preconditions:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
- role="identifier">is_unbounded</phrase><phrase role="special">()</phrase>
- <phrase role="special">||</phrase> <phrase role="special">(</phrase>
- <phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
- role="identifier">maximum_size</phrase><phrase role="special">()</phrase>
- <phrase role="special">>=</phrase> <phrase role="identifier">stack_size</phrase><phrase
- role="special">)</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Allocates memory of at least <code><phrase role="identifier">stack_size</phrase></code>
- bytes and stores a pointer to the stack and its actual size in <code><phrase
- role="identifier">sctx</phrase></code>. Depending on the architecture
- (the stack grows downwards/upwards) the stored address is the highest/lowest
- address of the stack.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="pooled_fixesize_deallocate_bridgehead">
- <phrase id="pooled_fixesize_deallocate"/>
- <link linkend="pooled_fixesize_deallocate">Member
- function <code>deallocate</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">deallocate</phrase><phrase role="special">(</phrase> <phrase role="identifier">stack_context</phrase> <phrase role="special">&</phrase> <phrase role="identifier">sctx</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Preconditions:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
- role="identifier">sp</phrase></code> is valid, <code><phrase role="identifier">traits_type</phrase><phrase
- role="special">::</phrase><phrase role="identifier">is_unbounded</phrase><phrase
- role="special">()</phrase> <phrase role="special">||</phrase> <phrase
- role="special">(</phrase> <phrase role="identifier">traits_type</phrase><phrase
- role="special">::</phrase><phrase role="identifier">maximum_size</phrase><phrase
- role="special">()</phrase> <phrase role="special">>=</phrase> <phrase
- role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
- role="identifier">size</phrase><phrase role="special">)</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Deallocates the stack space.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <note>
- <para>
- This stack allocator is not thread safe.
- </para>
- </note>
- <para>
- <bridgehead renderas="sect4" id="class_fixedsize_stack_bridgehead">
- <phrase id="class_fixedsize_stack"/>
- <link linkend="class_fixedsize_stack">Class
- <code>fixedsize_stack</code></link>
- </bridgehead>
- </para>
- <para>
- <emphasis role="bold">Boost.Fiber</emphasis> provides the class <link linkend="class_fixedsize_stack"><code>fixedsize_stack</code></link> which
- models the <link linkend="stack_allocator_concept"><emphasis>stack-allocator
- concept</emphasis></link>. In contrast to <link linkend="class_protected_fixedsize_stack"><code>protected_fixedsize_stack</code></link> it
- does not append a guard page at the end of each stack. The memory is simply
- managed by <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">malloc</phrase><phrase role="special">()</phrase></code>
- and <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">free</phrase><phrase role="special">()</phrase></code>.
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">context</phrase><phrase role="special">/</phrase><phrase role="identifier">fixedsize_stack</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">struct</phrase> <phrase role="identifier">fixedsize_stack</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">fixedsize_stack</phrase><phrase role="special">(</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">size</phrase> <phrase role="special">=</phrase> <phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase role="identifier">default_size</phrase><phrase role="special">());</phrase>
- <phrase role="identifier">stack_context</phrase> <phrase role="identifier">allocate</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">deallocate</phrase><phrase role="special">(</phrase> <phrase role="identifier">stack_context</phrase> <phrase role="special">&);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <para>
- <bridgehead renderas="sect4" id="fixedsize_allocate_bridgehead">
- <phrase id="fixedsize_allocate"/>
- <link linkend="fixedsize_allocate">Member function
- <code>allocate</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">stack_context</phrase> <phrase role="identifier">allocate</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Preconditions:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
- role="identifier">minimum_size</phrase><phrase role="special">()</phrase>
- <phrase role="special"><=</phrase> <phrase role="identifier">size</phrase></code>
- and <code><phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
- role="identifier">is_unbounded</phrase><phrase role="special">()</phrase>
- <phrase role="special">||</phrase> <phrase role="special">(</phrase>
- <phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
- role="identifier">maximum_size</phrase><phrase role="special">()</phrase>
- <phrase role="special">>=</phrase> <phrase role="identifier">size</phrase><phrase
- role="special">)</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Allocates memory of at least <code><phrase role="identifier">size</phrase></code>
- bytes and stores a pointer to the stack and its actual size in <code><phrase
- role="identifier">sctx</phrase></code>. Depending on the architecture
- (the stack grows downwards/upwards) the stored address is the highest/lowest
- address of the stack.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="fixesize_deallocate_bridgehead">
- <phrase id="fixesize_deallocate"/>
- <link linkend="fixesize_deallocate">Member
- function <code>deallocate</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">deallocate</phrase><phrase role="special">(</phrase> <phrase role="identifier">stack_context</phrase> <phrase role="special">&</phrase> <phrase role="identifier">sctx</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Preconditions:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
- role="identifier">sp</phrase></code> is valid, <code><phrase role="identifier">traits_type</phrase><phrase
- role="special">::</phrase><phrase role="identifier">minimum_size</phrase><phrase
- role="special">()</phrase> <phrase role="special"><=</phrase> <phrase
- role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
- role="identifier">size</phrase></code> and <code><phrase role="identifier">traits_type</phrase><phrase
- role="special">::</phrase><phrase role="identifier">is_unbounded</phrase><phrase
- role="special">()</phrase> <phrase role="special">||</phrase> <phrase
- role="special">(</phrase> <phrase role="identifier">traits_type</phrase><phrase
- role="special">::</phrase><phrase role="identifier">maximum_size</phrase><phrase
- role="special">()</phrase> <phrase role="special">>=</phrase> <phrase
- role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
- role="identifier">size</phrase><phrase role="special">)</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Deallocates the stack space.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <anchor id="segmented"/><bridgehead renderas="sect4" id="class_segmented_stack_bridgehead">
- <phrase id="class_segmented_stack"/>
- <link linkend="class_segmented_stack">Class
- <code>segmented_stack</code></link>
- </bridgehead>
- </para>
- <para>
- <emphasis role="bold">Boost.Fiber</emphasis> supports usage of a <link linkend="class_segmented_stack"><code>segmented_stack</code></link>,
- i.e. the stack grows on demand. The fiber is created with a minimal stack size
- which will be increased as required. Class <link linkend="class_segmented_stack"><code>segmented_stack</code></link> models
- the <link linkend="stack_allocator_concept"><emphasis>stack-allocator concept</emphasis></link>.
- In contrast to <link linkend="class_protected_fixedsize_stack"><code>protected_fixedsize_stack</code></link> and
- <link linkend="class_fixedsize_stack"><code>fixedsize_stack</code></link> it creates a stack which grows on demand.
- </para>
- <note>
- <para>
- Segmented stacks are currently only supported by <emphasis role="bold">gcc</emphasis>
- from version <emphasis role="bold">4.7</emphasis> and <emphasis role="bold">clang</emphasis>
- from version <emphasis role="bold">3.4</emphasis> onwards. In order to use
- a <link linkend="class_segmented_stack"><code>segmented_stack</code></link> <emphasis role="bold">Boost.Fiber</emphasis>
- must be built with property <code><phrase role="identifier">segmented</phrase><phrase
- role="special">-</phrase><phrase role="identifier">stacks</phrase></code>,
- e.g. <emphasis role="bold">toolset=gcc segmented-stacks=on</emphasis> and
- applying BOOST_USE_SEGMENTED_STACKS at b2/bjam command line.
- </para>
- </note>
- <note>
- <para>
- Segmented stacks can only be used with callcc() using property <code><phrase
- role="identifier">context</phrase><phrase role="special">-</phrase><phrase
- role="identifier">impl</phrase><phrase role="special">=</phrase><phrase role="identifier">ucontext</phrase></code>.
- </para>
- </note>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">segmented_stack</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">struct</phrase> <phrase role="identifier">segmented_stack</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">segmented_stack</phrase><phrase role="special">(</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">stack_size</phrase> <phrase role="special">=</phrase> <phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase role="identifier">default_size</phrase><phrase role="special">());</phrase>
- <phrase role="identifier">stack_context</phrase> <phrase role="identifier">allocate</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">deallocate</phrase><phrase role="special">(</phrase> <phrase role="identifier">stack_context</phrase> <phrase role="special">&);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <para>
- <bridgehead renderas="sect4" id="segmented_allocate_bridgehead">
- <phrase id="segmented_allocate"/>
- <link linkend="segmented_allocate">Member function
- <code>allocate</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">stack_context</phrase> <phrase role="identifier">allocate</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Preconditions:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
- role="identifier">minimum_size</phrase><phrase role="special">()</phrase>
- <phrase role="special"><=</phrase> <phrase role="identifier">size</phrase></code>
- and <code><phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
- role="identifier">is_unbounded</phrase><phrase role="special">()</phrase>
- <phrase role="special">||</phrase> <phrase role="special">(</phrase>
- <phrase role="identifier">traits_type</phrase><phrase role="special">::</phrase><phrase
- role="identifier">maximum_size</phrase><phrase role="special">()</phrase>
- <phrase role="special">>=</phrase> <phrase role="identifier">size</phrase><phrase
- role="special">)</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Allocates memory of at least <code><phrase role="identifier">size</phrase></code>
- bytes and stores a pointer to the stack and its actual size in <code><phrase
- role="identifier">sctx</phrase></code>. Depending on the architecture
- (the stack grows downwards/upwards) the stored address is the highest/lowest
- address of the stack.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="segmented_deallocate_bridgehead">
- <phrase id="segmented_deallocate"/>
- <link linkend="segmented_deallocate">Member
- function <code>deallocate</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">deallocate</phrase><phrase role="special">(</phrase> <phrase role="identifier">stack_context</phrase> <phrase role="special">&</phrase> <phrase role="identifier">sctx</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Preconditions:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
- role="identifier">sp</phrase></code> is valid, <code><phrase role="identifier">traits_type</phrase><phrase
- role="special">::</phrase><phrase role="identifier">minimum_size</phrase><phrase
- role="special">()</phrase> <phrase role="special"><=</phrase> <phrase
- role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
- role="identifier">size</phrase></code> and <code><phrase role="identifier">traits_type</phrase><phrase
- role="special">::</phrase><phrase role="identifier">is_unbounded</phrase><phrase
- role="special">()</phrase> <phrase role="special">||</phrase> <phrase
- role="special">(</phrase> <phrase role="identifier">traits_type</phrase><phrase
- role="special">::</phrase><phrase role="identifier">maximum_size</phrase><phrase
- role="special">()</phrase> <phrase role="special">>=</phrase> <phrase
- role="identifier">sctx</phrase><phrase role="special">.</phrase><phrase
- role="identifier">size</phrase><phrase role="special">)</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Deallocates the stack space.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <note>
- <para>
- If the library is compiled for segmented stacks, <link linkend="class_segmented_stack"><code>segmented_stack</code></link> is
- the only available stack allocator.
- </para>
- </note>
- <section id="fiber.stack.valgrind">
- <title><link linkend="fiber.stack.valgrind">Support for valgrind</link></title>
- <para>
- Running programs that switch stacks under valgrind causes problems. Property
- (b2 command-line) <code><phrase role="identifier">valgrind</phrase><phrase
- role="special">=</phrase><phrase role="identifier">on</phrase></code> let
- valgrind treat the memory regions as stack space which suppresses the errors.
- </para>
- </section>
- </section>
- <section id="fiber.synchronization">
- <title><anchor id="synchronization"/><link linkend="fiber.synchronization">Synchronization</link></title>
- <para>
- In general, <emphasis role="bold">Boost.Fiber</emphasis> synchronization objects
- can neither be moved nor copied. A synchronization object acts as a mutually-agreed
- rendezvous point between different fibers. If such an object were copied somewhere
- else, the new copy would have no consumers. If such an object were <emphasis>moved</emphasis>
- somewhere else, leaving the original instance in an unspecified state, existing
- consumers would behave strangely.
- </para>
- <para>
- The fiber synchronization objects provided by this library will, by default,
- safely synchronize fibers running on different threads. However, this level
- of synchronization can be removed (for performance) by building the library
- with <emphasis role="bold"><code><phrase role="identifier">BOOST_FIBERS_NO_ATOMICS</phrase></code></emphasis>
- defined. When the library is built with that macro, you must ensure that all
- the fibers referencing a particular synchronization object are running in the
- same thread.
- </para>
- <section id="fiber.synchronization.mutex_types">
- <title><link linkend="fiber.synchronization.mutex_types">Mutex Types</link></title>
- <para>
- <bridgehead renderas="sect4" id="class_mutex_bridgehead">
- <phrase id="class_mutex"/>
- <link linkend="class_mutex">Class <code>mutex</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">mutex</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">mutex</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">mutex</phrase><phrase role="special">();</phrase>
- <phrase role="special">~</phrase><phrase role="identifier">mutex</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">mutex</phrase><phrase role="special">(</phrase> <phrase role="identifier">mutex</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">mutex</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">mutex</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
- <phrase role="special">};</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <para>
- <link linkend="class_mutex"><code>mutex</code></link> provides an exclusive-ownership mutex. At most one fiber
- can own the lock on a given instance of <link linkend="class_mutex"><code>mutex</code></link> at any time. Multiple
- concurrent calls to <code><phrase role="identifier">lock</phrase><phrase
- role="special">()</phrase></code>, <code><phrase role="identifier">try_lock</phrase><phrase
- role="special">()</phrase></code> and <code><phrase role="identifier">unlock</phrase><phrase
- role="special">()</phrase></code> shall be permitted.
- </para>
- <para>
- Any fiber blocked in <code><phrase role="identifier">lock</phrase><phrase
- role="special">()</phrase></code> is suspended until the owning fiber releases
- the lock by calling <code><phrase role="identifier">unlock</phrase><phrase
- role="special">()</phrase></code>.
- </para>
- <para>
- <bridgehead renderas="sect4" id="mutex_lock_bridgehead">
- <phrase id="mutex_lock"/>
- <link linkend="mutex_lock">Member function <code>lock</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- The calling fiber doesn't own the mutex.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- The current fiber blocks until ownership can be obtained.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lock_error</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Error Conditions:</term>
- <listitem>
- <para>
- <emphasis role="bold">resource_deadlock_would_occur</emphasis>: if
- <code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
- already owns the mutex.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="mutex_try_lock_bridgehead">
- <phrase id="mutex_try_lock"/>
- <link linkend="mutex_try_lock">Member function <code>try_lock</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- The calling fiber doesn't own the mutex.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Attempt to obtain ownership for the current fiber without blocking.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if ownership was
- obtained for the current fiber, <code><phrase role="keyword">false</phrase></code>
- otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lock_error</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Error Conditions:</term>
- <listitem>
- <para>
- <emphasis role="bold">resource_deadlock_would_occur</emphasis>: if
- <code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
- already owns the mutex.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="mutex_unlock_bridgehead">
- <phrase id="mutex_unlock"/>
- <link linkend="mutex_unlock">Member function <code>unlock</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- The current fiber owns <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Releases a lock on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- by the current fiber.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lock_error</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Error Conditions:</term>
- <listitem>
- <para>
- <emphasis role="bold">operation_not_permitted</emphasis>: if <code><phrase
- role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
- does not own the mutex.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="class_timed_mutex_bridgehead">
- <phrase id="class_timed_mutex"/>
- <link linkend="class_timed_mutex">Class <code>timed_mutex</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">timed_mutex</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">timed_mutex</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">timed_mutex</phrase><phrase role="special">();</phrase>
- <phrase role="special">~</phrase><phrase role="identifier">timed_mutex</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">timed_mutex</phrase><phrase role="special">(</phrase> <phrase role="identifier">timed_mutex</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">timed_mutex</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">timed_mutex</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
- <phrase role="special">};</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <para>
- <link linkend="class_timed_mutex"><code>timed_mutex</code></link> provides an exclusive-ownership mutex. At most
- one fiber can own the lock on a given instance of <link linkend="class_timed_mutex"><code>timed_mutex</code></link> at
- any time. Multiple concurrent calls to <code><phrase role="identifier">lock</phrase><phrase
- role="special">()</phrase></code>, <code><phrase role="identifier">try_lock</phrase><phrase
- role="special">()</phrase></code>, <code><phrase role="identifier">try_lock_until</phrase><phrase
- role="special">()</phrase></code>, <code><phrase role="identifier">try_lock_for</phrase><phrase
- role="special">()</phrase></code> and <code><phrase role="identifier">unlock</phrase><phrase
- role="special">()</phrase></code> shall be permitted.
- </para>
- <para>
- <bridgehead renderas="sect4" id="timed_mutex_lock_bridgehead">
- <phrase id="timed_mutex_lock"/>
- <link linkend="timed_mutex_lock">Member function
- <code>lock</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- The calling fiber doesn't own the mutex.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- The current fiber blocks until ownership can be obtained.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lock_error</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Error Conditions:</term>
- <listitem>
- <para>
- <emphasis role="bold">resource_deadlock_would_occur</emphasis>: if
- <code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
- already owns the mutex.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="timed_mutex_try_lock_bridgehead">
- <phrase id="timed_mutex_try_lock"/>
- <link linkend="timed_mutex_try_lock">Member
- function <code>try_lock</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- The calling fiber doesn't own the mutex.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Attempt to obtain ownership for the current fiber without blocking.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if ownership was
- obtained for the current fiber, <code><phrase role="keyword">false</phrase></code>
- otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lock_error</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Error Conditions:</term>
- <listitem>
- <para>
- <emphasis role="bold">resource_deadlock_would_occur</emphasis>: if
- <code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
- already owns the mutex.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="timed_mutex_unlock_bridgehead">
- <phrase id="timed_mutex_unlock"/>
- <link linkend="timed_mutex_unlock">Member function
- <code>unlock</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- The current fiber owns <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Releases a lock on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- by the current fiber.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lock_error</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Error Conditions:</term>
- <listitem>
- <para>
- <emphasis role="bold">operation_not_permitted</emphasis>: if <code><phrase
- role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
- does not own the mutex.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="timed_mutex_try_lock_until_bridgehead">
- <phrase id="timed_mutex_try_lock_until"/>
- <link linkend="timed_mutex_try_lock_until">Templated
- member function <code>try_lock_until</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- The calling fiber doesn't own the mutex.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Attempt to obtain ownership for the current fiber. Blocks until ownership
- can be obtained, or the specified time is reached. If the specified
- time has already passed, behaves as <link linkend="timed_mutex_try_lock"><code>timed_mutex::try_lock()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if ownership was
- obtained for the current fiber, <code><phrase role="keyword">false</phrase></code>
- otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lock_error</phrase></code>, timeout-related
- exceptions.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Error Conditions:</term>
- <listitem>
- <para>
- <emphasis role="bold">resource_deadlock_would_occur</emphasis>: if
- <code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
- already owns the mutex.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="timed_mutex_try_lock_for_bridgehead">
- <phrase id="timed_mutex_try_lock_for"/>
- <link linkend="timed_mutex_try_lock_for">Templated
- member function <code>try_lock_for</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- The calling fiber doesn't own the mutex.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Attempt to obtain ownership for the current fiber. Blocks until ownership
- can be obtained, or the specified time is reached. If the specified
- time has already passed, behaves as <link linkend="timed_mutex_try_lock"><code>timed_mutex::try_lock()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if ownership was
- obtained for the current fiber, <code><phrase role="keyword">false</phrase></code>
- otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lock_error</phrase></code>, timeout-related
- exceptions.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Error Conditions:</term>
- <listitem>
- <para>
- <emphasis role="bold">resource_deadlock_would_occur</emphasis>: if
- <code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
- already owns the mutex.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="class_recursive_mutex_bridgehead">
- <phrase id="class_recursive_mutex"/>
- <link linkend="class_recursive_mutex">Class
- <code>recursive_mutex</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">recursive_mutex</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">recursive_mutex</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">recursive_mutex</phrase><phrase role="special">();</phrase>
- <phrase role="special">~</phrase><phrase role="identifier">recursive_mutex</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">recursive_mutex</phrase><phrase role="special">(</phrase> <phrase role="identifier">recursive_mutex</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">recursive_mutex</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">recursive_mutex</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
- <phrase role="special">};</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <para>
- <link linkend="class_recursive_mutex"><code>recursive_mutex</code></link> provides an exclusive-ownership recursive
- mutex. At most one fiber can own the lock on a given instance of <link linkend="class_recursive_mutex"><code>recursive_mutex</code></link> at
- any time. Multiple concurrent calls to <code><phrase role="identifier">lock</phrase><phrase
- role="special">()</phrase></code>, <code><phrase role="identifier">try_lock</phrase><phrase
- role="special">()</phrase></code> and <code><phrase role="identifier">unlock</phrase><phrase
- role="special">()</phrase></code> shall be permitted. A fiber that already
- has exclusive ownership of a given <link linkend="class_recursive_mutex"><code>recursive_mutex</code></link> instance
- can call <code><phrase role="identifier">lock</phrase><phrase role="special">()</phrase></code>
- or <code><phrase role="identifier">try_lock</phrase><phrase role="special">()</phrase></code>
- to acquire an additional level of ownership of the mutex. <code><phrase role="identifier">unlock</phrase><phrase
- role="special">()</phrase></code> must be called once for each level of ownership
- acquired by a single fiber before ownership can be acquired by another fiber.
- </para>
- <para>
- <bridgehead renderas="sect4" id="recursive_mutex_lock_bridgehead">
- <phrase id="recursive_mutex_lock"/>
- <link linkend="recursive_mutex_lock">Member
- function <code>lock</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- The current fiber blocks until ownership can be obtained.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="recursive_mutex_try_lock_bridgehead">
- <phrase id="recursive_mutex_try_lock"/>
- <link linkend="recursive_mutex_try_lock">Member
- function <code>try_lock</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Attempt to obtain ownership for the current fiber without blocking.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if ownership was
- obtained for the current fiber, <code><phrase role="keyword">false</phrase></code>
- otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="recursive_mutex_unlock_bridgehead">
- <phrase id="recursive_mutex_unlock"/>
- <link linkend="recursive_mutex_unlock">Member
- function <code>unlock</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Releases a lock on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- by the current fiber.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lock_error</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Error Conditions:</term>
- <listitem>
- <para>
- <emphasis role="bold">operation_not_permitted</emphasis>: if <code><phrase
- role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
- does not own the mutex.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="class_recursive_timed_mutex_bridgehead">
- <phrase id="class_recursive_timed_mutex"/>
- <link linkend="class_recursive_timed_mutex">Class
- <code>recursive_timed_mutex</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">recursive_timed_mutex</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">recursive_timed_mutex</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">recursive_timed_mutex</phrase><phrase role="special">();</phrase>
- <phrase role="special">~</phrase><phrase role="identifier">recursive_timed_mutex</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">recursive_timed_mutex</phrase><phrase role="special">(</phrase> <phrase role="identifier">recursive_timed_mutex</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">recursive_timed_mutex</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">recursive_timed_mutex</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
- <phrase role="special">};</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <para>
- <link linkend="class_recursive_timed_mutex"><code>recursive_timed_mutex</code></link> provides an exclusive-ownership
- recursive mutex. At most one fiber can own the lock on a given instance of
- <link linkend="class_recursive_timed_mutex"><code>recursive_timed_mutex</code></link> at any time. Multiple concurrent
- calls to <code><phrase role="identifier">lock</phrase><phrase role="special">()</phrase></code>,
- <code><phrase role="identifier">try_lock</phrase><phrase role="special">()</phrase></code>,
- <code><phrase role="identifier">try_lock_for</phrase><phrase role="special">()</phrase></code>,
- <code><phrase role="identifier">try_lock_until</phrase><phrase role="special">()</phrase></code>
- and <code><phrase role="identifier">unlock</phrase><phrase role="special">()</phrase></code>
- shall be permitted. A fiber that already has exclusive ownership of a given
- <link linkend="class_recursive_timed_mutex"><code>recursive_timed_mutex</code></link> instance can call <code><phrase
- role="identifier">lock</phrase><phrase role="special">()</phrase></code>,
- <code><phrase role="identifier">try_lock</phrase><phrase role="special">()</phrase></code>,
- <code><phrase role="identifier">try_lock_for</phrase><phrase role="special">()</phrase></code>
- or <code><phrase role="identifier">try_lock_until</phrase><phrase role="special">()</phrase></code>
- to acquire an additional level of ownership of the mutex. <code><phrase role="identifier">unlock</phrase><phrase
- role="special">()</phrase></code> must be called once for each level of ownership
- acquired by a single fiber before ownership can be acquired by another fiber.
- </para>
- <para>
- <bridgehead renderas="sect4" id="recursive_timed_mutex_lock_bridgehead">
- <phrase id="recursive_timed_mutex_lock"/>
- <link linkend="recursive_timed_mutex_lock">Member
- function <code>lock</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- The current fiber blocks until ownership can be obtained.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="recursive_timed_mutex_try_lock_bridgehead">
- <phrase id="recursive_timed_mutex_try_lock"/>
- <link linkend="recursive_timed_mutex_try_lock">Member
- function <code>try_lock</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Attempt to obtain ownership for the current fiber without blocking.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if ownership was
- obtained for the current fiber, <code><phrase role="keyword">false</phrase></code>
- otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="recursive_timed_mutex_unlock_bridgehead">
- <phrase id="recursive_timed_mutex_unlock"/>
- <link linkend="recursive_timed_mutex_unlock">Member
- function <code>unlock</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Releases a lock on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- by the current fiber.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lock_error</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Error Conditions:</term>
- <listitem>
- <para>
- <emphasis role="bold">operation_not_permitted</emphasis>: if <code><phrase
- role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase
- role="identifier">get_id</phrase><phrase role="special">()</phrase></code>
- does not own the mutex.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="recursive_timed_mutex_try_lock_until_bridgehead">
- <phrase id="recursive_timed_mutex_try_lock_until"/>
- <link linkend="recursive_timed_mutex_try_lock_until">Templated
- member function <code>try_lock_until</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Attempt to obtain ownership for the current fiber. Blocks until ownership
- can be obtained, or the specified time is reached. If the specified
- time has already passed, behaves as <link linkend="recursive_timed_mutex_try_lock"><code>recursive_timed_mutex::try_lock()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if ownership was
- obtained for the current fiber, <code><phrase role="keyword">false</phrase></code>
- otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Timeout-related exceptions.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="recursive_timed_mutex_try_lock_for_bridgehead">
- <phrase id="recursive_timed_mutex_try_lock_for"/>
- <link linkend="recursive_timed_mutex_try_lock_for">Templated
- member function <code>try_lock_for</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">try_lock_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Attempt to obtain ownership for the current fiber. Blocks until ownership
- can be obtained, or the specified time is reached. If the specified
- time has already passed, behaves as <link linkend="recursive_timed_mutex_try_lock"><code>recursive_timed_mutex::try_lock()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if ownership was
- obtained for the current fiber, <code><phrase role="keyword">false</phrase></code>
- otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Timeout-related exceptions.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section id="fiber.synchronization.conditions">
- <title><link linkend="fiber.synchronization.conditions">Condition Variables</link></title>
- <bridgehead renderas="sect4" id="fiber.synchronization.conditions.h0">
- <phrase id="fiber.synchronization.conditions.synopsis"/><link linkend="fiber.synchronization.conditions.synopsis">Synopsis</link>
- </bridgehead>
- <programlisting><phrase role="keyword">enum</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">cv_status</phrase><phrase role="special">;</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">no_timeout</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">timeout</phrase>
- <phrase role="special">};</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">condition_variable</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">condition_variable_any</phrase><phrase role="special">;</phrase>
- </programlisting>
- <para>
- The class <link linkend="class_condition_variable"><code>condition_variable</code></link> provides a mechanism
- for a fiber to wait for notification from another fiber. When the fiber awakens
- from the wait, then it checks to see if the appropriate condition is now
- true, and continues if so. If the condition is not true, then the fiber calls
- <code><phrase role="identifier">wait</phrase></code> again to resume waiting.
- In the simplest case, this condition is just a boolean variable:
- </para>
- <programlisting><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">condition_variable</phrase> <phrase role="identifier">cond</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="identifier">mtx</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">data_ready</phrase> <phrase role="special">=</phrase> <phrase role="keyword">false</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">process_data</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait_for_data_to_process</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
- <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">></phrase> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">data_ready</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">cond</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase> <phrase role="comment">// release lk</phrase>
- <phrase role="identifier">process_data</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- <para>
- Notice that the <code><phrase role="identifier">lk</phrase></code> is passed
- to <link linkend="condition_variable_wait"><code>condition_variable::wait()</code></link>: <code><phrase role="identifier">wait</phrase><phrase
- role="special">()</phrase></code> will atomically add the fiber to the set
- of fibers waiting on the condition variable, and unlock the <link linkend="class_mutex"><code>mutex</code></link>.
- When the fiber is awakened, the <code><phrase role="identifier">mutex</phrase></code>
- will be locked again before the call to <code><phrase role="identifier">wait</phrase><phrase
- role="special">()</phrase></code> returns. This allows other fibers to acquire
- the <code><phrase role="identifier">mutex</phrase></code> in order to update
- the shared data, and ensures that the data associated with the condition
- is correctly synchronized.
- </para>
- <para>
- <code><phrase role="identifier">wait_for_data_to_process</phrase><phrase
- role="special">()</phrase></code> could equivalently be written:
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">wait_for_data_to_process</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
- <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">></phrase> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx</phrase><phrase role="special">);</phrase>
- <phrase role="comment">// make condition_variable::wait() perform the loop</phrase>
- <phrase role="identifier">cond</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">data_ready</phrase><phrase role="special">;</phrase> <phrase role="special">});</phrase>
- <phrase role="special">}</phrase> <phrase role="comment">// release lk</phrase>
- <phrase role="identifier">process_data</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- <para>
- In the meantime, another fiber sets <code><phrase role="identifier">data_ready</phrase></code>
- to <code><phrase role="keyword">true</phrase></code>, and then calls either
- <link linkend="condition_variable_notify_one"><code>condition_variable::notify_one()</code></link> or <link linkend="condition_variable_notify_all"><code>condition_variable::notify_all()</code></link> on
- the <link linkend="class_condition_variable"><code>condition_variable</code></link> <code><phrase role="identifier">cond</phrase></code>
- to wake one waiting fiber or all the waiting fibers respectively.
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">retrieve_data</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">prepare_data</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">prepare_data_for_processing</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">retrieve_data</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">prepare_data</phrase><phrase role="special">();</phrase>
- <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">></phrase> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">data_ready</phrase> <phrase role="special">=</phrase> <phrase role="keyword">true</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">cond</phrase><phrase role="special">.</phrase><phrase role="identifier">notify_one</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- <para>
- Note that the same <link linkend="class_mutex"><code>mutex</code></link> is locked before the shared data is updated,
- but that the <code><phrase role="identifier">mutex</phrase></code> does not
- have to be locked across the call to <link linkend="condition_variable_notify_one"><code>condition_variable::notify_one()</code></link>.
- </para>
- <para>
- Locking is important because the synchronization objects provided by <emphasis
- role="bold">Boost.Fiber</emphasis> can be used to synchronize fibers running
- on different threads.
- </para>
- <para>
- <emphasis role="bold">Boost.Fiber</emphasis> provides both <link linkend="class_condition_variable"><code>condition_variable</code></link> and
- <link linkend="class_condition_variable_any"><code>condition_variable_any</code></link>. <code><phrase role="identifier">boost</phrase><phrase
- role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase
- role="special">::</phrase><phrase role="identifier">condition_variable</phrase></code>
- can only wait on <ulink url="http://en.cppreference.com/w/cpp/thread/unique_lock"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase></code></ulink><code><phrase
- role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase
- role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase
- role="special">::</phrase></code><link linkend="class_mutex"><code>mutex</code></link><code> <phrase role="special">></phrase></code>
- while <code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase
- role="identifier">condition_variable_any</phrase></code> can wait on user-defined
- lock types.
- </para>
- <anchor id="condition_variable_spurious_wakeups"/>
- <bridgehead renderas="sect4" id="fiber.synchronization.conditions.h1">
- <phrase id="fiber.synchronization.conditions.no_spurious_wakeups"/><link
- linkend="fiber.synchronization.conditions.no_spurious_wakeups">No Spurious
- Wakeups</link>
- </bridgehead>
- <para>
- Neither <link linkend="class_condition_variable"><code>condition_variable</code></link> nor <link linkend="class_condition_variable_any"><code>condition_variable_any</code></link> are
- subject to spurious wakeup: <link linkend="condition_variable_wait"><code>condition_variable::wait()</code></link> can
- only wake up when <link linkend="condition_variable_notify_one"><code>condition_variable::notify_one()</code></link> or
- <link linkend="condition_variable_notify_all"><code>condition_variable::notify_all()</code></link> is called. Even
- so, it is prudent to use one of the <code><phrase role="identifier">wait</phrase><phrase
- role="special">(</phrase> <phrase role="identifier">lock</phrase><phrase
- role="special">,</phrase> <phrase role="identifier">predicate</phrase> <phrase
- role="special">)</phrase></code> overloads.
- </para>
- <para>
- Consider a set of consumer fibers processing items from a <ulink url="http://en.cppreference.com/w/cpp/container/queue"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">queue</phrase></code></ulink>.
- The queue is continually populated by a set of producer fibers.
- </para>
- <para>
- The consumer fibers might reasonably wait on a <code><phrase role="identifier">condition_variable</phrase></code>
- as long as the queue remains <ulink url="http://en.cppreference.com/w/cpp/container/queue/empty"><code><phrase
- role="identifier">empty</phrase><phrase role="special">()</phrase></code></ulink>.
- </para>
- <para>
- Because producer fibers might <ulink url="http://en.cppreference.com/w/cpp/container/queue/push"><code><phrase
- role="identifier">push</phrase><phrase role="special">()</phrase></code></ulink>
- items to the queue in bursts, they call <link linkend="condition_variable_notify_all"><code>condition_variable::notify_all()</code></link> rather
- than <link linkend="condition_variable_notify_one"><code>condition_variable::notify_one()</code></link>.
- </para>
- <para>
- But a given consumer fiber might well wake up from <link linkend="condition_variable_wait"><code>condition_variable::wait()</code></link> and
- find the queue <code><phrase role="identifier">empty</phrase><phrase role="special">()</phrase></code>,
- because other consumer fibers might already have processed all pending items.
- </para>
- <para>
- (See also <link linkend="spurious_wakeup">spurious wakeup</link>.)
- </para>
- <anchor id="class_cv_status"/>
- <bridgehead renderas="sect4" id="fiber.synchronization.conditions.h2">
- <phrase id="fiber.synchronization.conditions.enumeration__code__phrase_role__identifier__cv_status__phrase___code_"/><link
- linkend="fiber.synchronization.conditions.enumeration__code__phrase_role__identifier__cv_status__phrase___code_">Enumeration
- <code><phrase role="identifier">cv_status</phrase></code></link>
- </bridgehead>
- <para>
- A timed wait operation might return because of timeout or not.
- </para>
- <programlisting><phrase role="keyword">enum</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">cv_status</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">no_timeout</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">timeout</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- <bridgehead renderas="sect4" id="fiber.synchronization.conditions.h3">
- <phrase id="fiber.synchronization.conditions._code__phrase_role__identifier__no_timeout__phrase___code_"/><link
- linkend="fiber.synchronization.conditions._code__phrase_role__identifier__no_timeout__phrase___code_"><code><phrase
- role="identifier">no_timeout</phrase></code></link>
- </bridgehead>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- The condition variable was awakened with <code><phrase role="identifier">notify_one</phrase></code>
- or <code><phrase role="identifier">notify_all</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect4" id="fiber.synchronization.conditions.h4">
- <phrase id="fiber.synchronization.conditions._code__phrase_role__identifier__timeout__phrase___code_"/><link
- linkend="fiber.synchronization.conditions._code__phrase_role__identifier__timeout__phrase___code_"><code><phrase
- role="identifier">timeout</phrase></code></link>
- </bridgehead>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- The condition variable was awakened by timeout.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="class_condition_variable_any_bridgehead">
- <phrase id="class_condition_variable_any"/>
- <link linkend="class_condition_variable_any">Class
- <code>condition_variable_any</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">condition_variable</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">class</phrase> condition_variable_any <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- condition_variable_any<phrase role="special">();</phrase>
- <phrase role="special">~</phrase>condition_variable_any<phrase role="special">();</phrase>
- condition_variable_any<phrase role="special">(</phrase> condition_variable_any <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- condition_variable_any <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> condition_variable_any <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">notify_one</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">notify_all</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- template< typename LockType >
- void <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename LockType, typename <phrase role="identifier">Pred</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&,</phrase> <phrase role="identifier">Pred</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename LockType, typename <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">cv_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename LockType, typename <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Pred</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&,</phrase>
- <phrase role="identifier">Pred</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename LockType, typename <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">cv_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename LockType, typename <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Pred</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&,</phrase>
- <phrase role="identifier">Pred</phrase><phrase role="special">);</phrase>
- <phrase role="special">};</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <bridgehead renderas="sect4" id="fiber.synchronization.conditions.h5">
- <phrase id="fiber.synchronization.conditions.constructor"/><link linkend="fiber.synchronization.conditions.constructor">Constructor</link>
- </bridgehead>
- <programlisting>condition_variable_any<phrase role="special">()</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Creates the object.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect4" id="fiber.synchronization.conditions.h6">
- <phrase id="fiber.synchronization.conditions.destructor"/><link linkend="fiber.synchronization.conditions.destructor">Destructor</link>
- </bridgehead>
- <programlisting><phrase role="special">~</phrase>condition_variable_any<phrase role="special">()</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- All fibers waiting on <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code> have been notified by a call to
- <code><phrase role="identifier">notify_one</phrase></code> or <code><phrase
- role="identifier">notify_all</phrase></code> (though the respective
- calls to <code><phrase role="identifier">wait</phrase></code>, <code><phrase
- role="identifier">wait_for</phrase></code> or <code><phrase role="identifier">wait_until</phrase></code>
- need not have returned).
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Destroys the object.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="condition_variable_any_notify_one_bridgehead">
- <phrase id="condition_variable_any_notify_one"/>
- <link linkend="condition_variable_any_notify_one">Member
- function <code>notify_one</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">notify_one</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- If any fibers are currently <link linkend="blocking"><emphasis>blocked</emphasis></link>
- waiting on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- in a call to <code><phrase role="identifier">wait</phrase></code>,
- <code><phrase role="identifier">wait_for</phrase></code> or <code><phrase
- role="identifier">wait_until</phrase></code>, unblocks one of those
- fibers.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- It is arbitrary which waiting fiber is resumed.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="condition_variable_any_notify_all_bridgehead">
- <phrase id="condition_variable_any_notify_all"/>
- <link linkend="condition_variable_any_notify_all">Member
- function <code>notify_all</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">notify_all</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- If any fibers are currently <link linkend="blocking"><emphasis>blocked</emphasis></link>
- waiting on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- in a call to <code><phrase role="identifier">wait</phrase></code>,
- <code><phrase role="identifier">wait_for</phrase></code> or <code><phrase
- role="identifier">wait_until</phrase></code>, unblocks all of those
- fibers.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- This is why a waiting fiber must <emphasis>also</emphasis> check for
- the desired program state using a mechanism external to the <code>condition_variable_any</code>,
- and retry the wait until that state is reached. A fiber waiting on
- a <code>condition_variable_any</code> might well wake up a number of times before
- the desired state is reached.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="condition_variable_any_wait_bridgehead">
- <phrase id="condition_variable_any_wait"/>
- <link linkend="condition_variable_any_wait">Templated
- member function <code>wait</code>()</link>
- </bridgehead>
- </para>
- <programlisting>template< typename LockType >
- void <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&</phrase> <phrase role="identifier">lk</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename LockType, typename <phrase role="identifier">Pred</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="identifier">Pred</phrase> <phrase role="identifier">pred</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lk</phrase></code> is locked by the
- current fiber, and either no other fiber is currently waiting on <code><phrase
- role="special">*</phrase><phrase role="keyword">this</phrase></code>,
- or the execution of the <ulink url="http://en.cppreference.com/w/cpp/thread/unique_lock/mutex"><code><phrase
- role="identifier">mutex</phrase><phrase role="special">()</phrase></code></ulink>
- member function on the <code><phrase role="identifier">lk</phrase></code>
- objects supplied in the calls to <code><phrase role="identifier">wait</phrase></code>
- in all the fibers currently waiting on <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code> would return the same value as
- <code><phrase role="identifier">lk</phrase><phrase role="special">-></phrase><phrase
- role="identifier">mutex</phrase><phrase role="special">()</phrase></code>
- for this call to <code><phrase role="identifier">wait</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Atomically call <code><phrase role="identifier">lk</phrase><phrase
- role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase
- role="special">()</phrase></code> and blocks the current fiber. The
- fiber will unblock when notified by a call to <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">notify_one</phrase><phrase
- role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">notify_all</phrase><phrase
- role="special">()</phrase></code>. When the fiber is unblocked (for
- whatever reason), the lock is reacquired by invoking <code><phrase
- role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
- role="identifier">lock</phrase><phrase role="special">()</phrase></code>
- before the call to <code><phrase role="identifier">wait</phrase></code>
- returns. The lock is also reacquired by invoking <code><phrase role="identifier">lk</phrase><phrase
- role="special">.</phrase><phrase role="identifier">lock</phrase><phrase
- role="special">()</phrase></code> if the function exits with an exception.
- The member function accepting <code><phrase role="identifier">pred</phrase></code>
- is shorthand for:
- <programlisting><phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">pred</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postcondition:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lk</phrase></code> is locked by the
- current fiber.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">fiber_error</phrase></code> if an error
- occurs.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- The Precondition is a bit dense. It merely states that all the fibers
- concurrently calling <code><phrase role="identifier">wait</phrase></code>
- on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- must wait on <code><phrase role="identifier">lk</phrase></code> objects
- governing the <emphasis>same</emphasis> <link linkend="class_mutex"><code>mutex</code></link>. Three distinct
- objects are involved in any <code>condition_variable_any::wait()</code> call: the
- <code>condition_variable_any</code> itself, the <code><phrase role="identifier">mutex</phrase></code>
- coordinating access between fibers and a local lock object (e.g. <ulink
- url="http://en.cppreference.com/w/cpp/thread/unique_lock"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">unique_lock</phrase></code></ulink>). In general,
- you can partition the lifespan of a given <code>condition_variable_any</code> instance
- into periods with one or more fibers waiting on it, separated by periods
- when no fibers are waiting on it. When more than one fiber is waiting
- on that <code>condition_variable_any</code>, all must pass lock objects referencing
- the <emphasis>same</emphasis> <code><phrase role="identifier">mutex</phrase></code>
- instance.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="condition_variable_any_wait_until_bridgehead">
- <phrase id="condition_variable_any_wait_until"/>
- <link linkend="condition_variable_any_wait_until">Templated
- member function <code>wait_until</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename LockType, typename <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">cv_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename LockType, typename <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Pred</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">Pred</phrase> <phrase role="identifier">pred</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lk</phrase></code> is locked by the
- current fiber, and either no other fiber is currently waiting on <code><phrase
- role="special">*</phrase><phrase role="keyword">this</phrase></code>,
- or the execution of the <code><phrase role="identifier">mutex</phrase><phrase
- role="special">()</phrase></code> member function on the <code><phrase
- role="identifier">lk</phrase></code> objects supplied in the calls
- to <code><phrase role="identifier">wait</phrase></code>, <code><phrase
- role="identifier">wait_for</phrase></code> or <code><phrase role="identifier">wait_until</phrase></code>
- in all the fibers currently waiting on <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code> would return the same value as
- <code><phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
- role="identifier">mutex</phrase><phrase role="special">()</phrase></code>
- for this call to <code><phrase role="identifier">wait_until</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Atomically call <code><phrase role="identifier">lk</phrase><phrase
- role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase
- role="special">()</phrase></code> and blocks the current fiber. The
- fiber will unblock when notified by a call to <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">notify_one</phrase><phrase
- role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">notify_all</phrase><phrase
- role="special">()</phrase></code>, when the system time would be equal
- to or later than the specified <code><phrase role="identifier">abs_time</phrase></code>.
- When the fiber is unblocked (for whatever reason), the lock is reacquired
- by invoking <code><phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
- role="identifier">lock</phrase><phrase role="special">()</phrase></code>
- before the call to <code><phrase role="identifier">wait_until</phrase></code>
- returns. The lock is also reacquired by invoking <code><phrase role="identifier">lk</phrase><phrase
- role="special">.</phrase><phrase role="identifier">lock</phrase><phrase
- role="special">()</phrase></code> if the function exits with an exception.
- The member function accepting <code><phrase role="identifier">pred</phrase></code>
- is shorthand for:
- <programlisting><phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">pred</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase role="identifier">timeout</phrase> <phrase role="special">==</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">pred</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">return</phrase> <phrase role="keyword">true</phrase><phrase role="special">;</phrase>
- </programlisting>
- That is, even if <code><phrase role="identifier">wait_until</phrase><phrase
- role="special">()</phrase></code> times out, it can still return <code><phrase
- role="keyword">true</phrase></code> if <code><phrase role="identifier">pred</phrase><phrase
- role="special">()</phrase></code> returns <code><phrase role="keyword">true</phrase></code>
- at that time.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postcondition:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lk</phrase></code> is locked by the
- current fiber.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">fiber_error</phrase></code> if an error
- occurs or timeout-related exceptions.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- The overload without <code><phrase role="identifier">pred</phrase></code>
- returns <code><phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase
- role="identifier">no_timeout</phrase></code> if awakened by <code><phrase
- role="identifier">notify_one</phrase><phrase role="special">()</phrase></code>
- or <code><phrase role="identifier">notify_all</phrase><phrase role="special">()</phrase></code>,
- or <code><phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase
- role="identifier">timeout</phrase></code> if awakened because the system
- time is past <code><phrase role="identifier">abs_time</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- The overload accepting <code><phrase role="identifier">pred</phrase></code>
- returns <code><phrase role="keyword">false</phrase></code> if the call
- is returning because the time specified by <code><phrase role="identifier">abs_time</phrase></code>
- was reached and the predicate returns <code><phrase role="keyword">false</phrase></code>,
- <code><phrase role="keyword">true</phrase></code> otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- See <emphasis role="bold">Note</emphasis> for <link linkend="condition_variable_any_wait"><code>condition_variable_any::wait()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="condition_variable_any_wait_for_bridgehead">
- <phrase id="condition_variable_any_wait_for"/>
- <link linkend="condition_variable_any_wait_for">Templated
- member function <code>wait_for</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename LockType, typename <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">cv_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">rel_time</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename LockType, typename <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Pred</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> LockType <phrase role="special">&</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">rel_time</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">Pred</phrase> <phrase role="identifier">pred</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lk</phrase></code> is locked by the
- current fiber, and either no other fiber is currently waiting on <code><phrase
- role="special">*</phrase><phrase role="keyword">this</phrase></code>,
- or the execution of the <code><phrase role="identifier">mutex</phrase><phrase
- role="special">()</phrase></code> member function on the <code><phrase
- role="identifier">lk</phrase></code> objects supplied in the calls
- to <code><phrase role="identifier">wait</phrase></code>, <code><phrase
- role="identifier">wait_for</phrase></code> or <code><phrase role="identifier">wait_until</phrase></code>
- in all the fibers currently waiting on <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code> would return the same value as
- <code><phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
- role="identifier">mutex</phrase><phrase role="special">()</phrase></code>
- for this call to <code><phrase role="identifier">wait_for</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Atomically call <code><phrase role="identifier">lk</phrase><phrase
- role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase
- role="special">()</phrase></code> and blocks the current fiber. The
- fiber will unblock when notified by a call to <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">notify_one</phrase><phrase
- role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">notify_all</phrase><phrase
- role="special">()</phrase></code>, when a time interval equal to or
- greater than the specified <code><phrase role="identifier">rel_time</phrase></code>
- has elapsed. When the fiber is unblocked (for whatever reason), the
- lock is reacquired by invoking <code><phrase role="identifier">lk</phrase><phrase
- role="special">.</phrase><phrase role="identifier">lock</phrase><phrase
- role="special">()</phrase></code> before the call to <code><phrase
- role="identifier">wait</phrase></code> returns. The lock is also reacquired
- by invoking <code><phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
- role="identifier">lock</phrase><phrase role="special">()</phrase></code>
- if the function exits with an exception. The <code><phrase role="identifier">wait_for</phrase><phrase
- role="special">()</phrase></code> member function accepting <code><phrase
- role="identifier">pred</phrase></code> is shorthand for:
- <programlisting><phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">pred</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase role="identifier">timeout</phrase> <phrase role="special">==</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="identifier">rel_time</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">pred</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">return</phrase> <phrase role="keyword">true</phrase><phrase role="special">;</phrase>
- </programlisting>
- (except of course that <code><phrase role="identifier">rel_time</phrase></code>
- is adjusted for each iteration). The point is that, even if <code><phrase
- role="identifier">wait_for</phrase><phrase role="special">()</phrase></code>
- times out, it can still return <code><phrase role="keyword">true</phrase></code>
- if <code><phrase role="identifier">pred</phrase><phrase role="special">()</phrase></code>
- returns <code><phrase role="keyword">true</phrase></code> at that time.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postcondition:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lk</phrase></code> is locked by the
- current fiber.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">fiber_error</phrase></code> if an error
- occurs or timeout-related exceptions.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- The overload without <code><phrase role="identifier">pred</phrase></code>
- returns <code><phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase
- role="identifier">no_timeout</phrase></code> if awakened by <code><phrase
- role="identifier">notify_one</phrase><phrase role="special">()</phrase></code>
- or <code><phrase role="identifier">notify_all</phrase><phrase role="special">()</phrase></code>,
- or <code><phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase
- role="identifier">timeout</phrase></code> if awakened because at least
- <code><phrase role="identifier">rel_time</phrase></code> has elapsed.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- The overload accepting <code><phrase role="identifier">pred</phrase></code>
- returns <code><phrase role="keyword">false</phrase></code> if the call
- is returning because at least <code><phrase role="identifier">rel_time</phrase></code>
- has elapsed and the predicate returns <code><phrase role="keyword">false</phrase></code>,
- <code><phrase role="keyword">true</phrase></code> otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- See <emphasis role="bold">Note</emphasis> for <link linkend="condition_variable_any_wait"><code>condition_variable_any::wait()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="class_condition_variable_bridgehead">
- <phrase id="class_condition_variable"/>
- <link linkend="class_condition_variable">Class
- <code>condition_variable</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">condition_variable</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">class</phrase> condition_variable <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- condition_variable<phrase role="special">();</phrase>
- <phrase role="special">~</phrase>condition_variable<phrase role="special">();</phrase>
- condition_variable<phrase role="special">(</phrase> condition_variable <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- condition_variable <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> condition_variable <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">notify_one</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">notify_all</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- void <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <phrase role="special">&);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename <phrase role="identifier">Pred</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <phrase role="special">&,</phrase> <phrase role="identifier">Pred</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">cv_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <phrase role="special">&,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Pred</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <phrase role="special">&,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&,</phrase>
- <phrase role="identifier">Pred</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">cv_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <phrase role="special">&,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Pred</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <phrase role="special">&,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&,</phrase>
- <phrase role="identifier">Pred</phrase><phrase role="special">);</phrase>
- <phrase role="special">};</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <bridgehead renderas="sect4" id="fiber.synchronization.conditions.h7">
- <phrase id="fiber.synchronization.conditions.constructor0"/><link linkend="fiber.synchronization.conditions.constructor0">Constructor</link>
- </bridgehead>
- <programlisting>condition_variable<phrase role="special">()</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Creates the object.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect4" id="fiber.synchronization.conditions.h8">
- <phrase id="fiber.synchronization.conditions.destructor0"/><link linkend="fiber.synchronization.conditions.destructor0">Destructor</link>
- </bridgehead>
- <programlisting><phrase role="special">~</phrase>condition_variable<phrase role="special">()</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- All fibers waiting on <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code> have been notified by a call to
- <code><phrase role="identifier">notify_one</phrase></code> or <code><phrase
- role="identifier">notify_all</phrase></code> (though the respective
- calls to <code><phrase role="identifier">wait</phrase></code>, <code><phrase
- role="identifier">wait_for</phrase></code> or <code><phrase role="identifier">wait_until</phrase></code>
- need not have returned).
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Destroys the object.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="condition_variable_notify_one_bridgehead">
- <phrase id="condition_variable_notify_one"/>
- <link linkend="condition_variable_notify_one">Member
- function <code>notify_one</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">notify_one</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- If any fibers are currently <link linkend="blocking"><emphasis>blocked</emphasis></link>
- waiting on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- in a call to <code><phrase role="identifier">wait</phrase></code>,
- <code><phrase role="identifier">wait_for</phrase></code> or <code><phrase
- role="identifier">wait_until</phrase></code>, unblocks one of those
- fibers.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- It is arbitrary which waiting fiber is resumed.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="condition_variable_notify_all_bridgehead">
- <phrase id="condition_variable_notify_all"/>
- <link linkend="condition_variable_notify_all">Member
- function <code>notify_all</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">notify_all</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- If any fibers are currently <link linkend="blocking"><emphasis>blocked</emphasis></link>
- waiting on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- in a call to <code><phrase role="identifier">wait</phrase></code>,
- <code><phrase role="identifier">wait_for</phrase></code> or <code><phrase
- role="identifier">wait_until</phrase></code>, unblocks all of those
- fibers.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- This is why a waiting fiber must <emphasis>also</emphasis> check for
- the desired program state using a mechanism external to the <code>condition_variable</code>,
- and retry the wait until that state is reached. A fiber waiting on
- a <code>condition_variable</code> might well wake up a number of times before the
- desired state is reached.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="condition_variable_wait_bridgehead">
- <phrase id="condition_variable_wait"/>
- <link linkend="condition_variable_wait">Templated
- member function <code>wait</code>()</link>
- </bridgehead>
- </para>
- <programlisting>void <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <phrase role="special">&</phrase> <phrase role="identifier">lk</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename <phrase role="identifier">Pred</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <phrase role="special">&</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="identifier">Pred</phrase> <phrase role="identifier">pred</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lk</phrase></code> is locked by the
- current fiber, and either no other fiber is currently waiting on <code><phrase
- role="special">*</phrase><phrase role="keyword">this</phrase></code>,
- or the execution of the <ulink url="http://en.cppreference.com/w/cpp/thread/unique_lock/mutex"><code><phrase
- role="identifier">mutex</phrase><phrase role="special">()</phrase></code></ulink>
- member function on the <code><phrase role="identifier">lk</phrase></code>
- objects supplied in the calls to <code><phrase role="identifier">wait</phrase></code>
- in all the fibers currently waiting on <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code> would return the same value as
- <code><phrase role="identifier">lk</phrase><phrase role="special">-></phrase><phrase
- role="identifier">mutex</phrase><phrase role="special">()</phrase></code>
- for this call to <code><phrase role="identifier">wait</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Atomically call <code><phrase role="identifier">lk</phrase><phrase
- role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase
- role="special">()</phrase></code> and blocks the current fiber. The
- fiber will unblock when notified by a call to <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">notify_one</phrase><phrase
- role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">notify_all</phrase><phrase
- role="special">()</phrase></code>. When the fiber is unblocked (for
- whatever reason), the lock is reacquired by invoking <code><phrase
- role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
- role="identifier">lock</phrase><phrase role="special">()</phrase></code>
- before the call to <code><phrase role="identifier">wait</phrase></code>
- returns. The lock is also reacquired by invoking <code><phrase role="identifier">lk</phrase><phrase
- role="special">.</phrase><phrase role="identifier">lock</phrase><phrase
- role="special">()</phrase></code> if the function exits with an exception.
- The member function accepting <code><phrase role="identifier">pred</phrase></code>
- is shorthand for:
- <programlisting><phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">pred</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">wait</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postcondition:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lk</phrase></code> is locked by the
- current fiber.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">fiber_error</phrase></code> if an error
- occurs.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- The Precondition is a bit dense. It merely states that all the fibers
- concurrently calling <code><phrase role="identifier">wait</phrase></code>
- on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- must wait on <code><phrase role="identifier">lk</phrase></code> objects
- governing the <emphasis>same</emphasis> <link linkend="class_mutex"><code>mutex</code></link>. Three distinct
- objects are involved in any <code>condition_variable::wait()</code> call: the <code>condition_variable</code> itself,
- the <code><phrase role="identifier">mutex</phrase></code> coordinating
- access between fibers and a local lock object (e.g. <ulink url="http://en.cppreference.com/w/cpp/thread/unique_lock"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">unique_lock</phrase></code></ulink>). In general,
- you can partition the lifespan of a given <code>condition_variable</code> instance
- into periods with one or more fibers waiting on it, separated by periods
- when no fibers are waiting on it. When more than one fiber is waiting
- on that <code>condition_variable</code>, all must pass lock objects referencing
- the <emphasis>same</emphasis> <code><phrase role="identifier">mutex</phrase></code>
- instance.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="condition_variable_wait_until_bridgehead">
- <phrase id="condition_variable_wait_until"/>
- <link linkend="condition_variable_wait_until">Templated
- member function <code>wait_until</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">cv_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <phrase role="special">&</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Pred</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <phrase role="special">&</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">Pred</phrase> <phrase role="identifier">pred</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lk</phrase></code> is locked by the
- current fiber, and either no other fiber is currently waiting on <code><phrase
- role="special">*</phrase><phrase role="keyword">this</phrase></code>,
- or the execution of the <code><phrase role="identifier">mutex</phrase><phrase
- role="special">()</phrase></code> member function on the <code><phrase
- role="identifier">lk</phrase></code> objects supplied in the calls
- to <code><phrase role="identifier">wait</phrase></code>, <code><phrase
- role="identifier">wait_for</phrase></code> or <code><phrase role="identifier">wait_until</phrase></code>
- in all the fibers currently waiting on <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code> would return the same value as
- <code><phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
- role="identifier">mutex</phrase><phrase role="special">()</phrase></code>
- for this call to <code><phrase role="identifier">wait_until</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Atomically call <code><phrase role="identifier">lk</phrase><phrase
- role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase
- role="special">()</phrase></code> and blocks the current fiber. The
- fiber will unblock when notified by a call to <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">notify_one</phrase><phrase
- role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">notify_all</phrase><phrase
- role="special">()</phrase></code>, when the system time would be equal
- to or later than the specified <code><phrase role="identifier">abs_time</phrase></code>.
- When the fiber is unblocked (for whatever reason), the lock is reacquired
- by invoking <code><phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
- role="identifier">lock</phrase><phrase role="special">()</phrase></code>
- before the call to <code><phrase role="identifier">wait_until</phrase></code>
- returns. The lock is also reacquired by invoking <code><phrase role="identifier">lk</phrase><phrase
- role="special">.</phrase><phrase role="identifier">lock</phrase><phrase
- role="special">()</phrase></code> if the function exits with an exception.
- The member function accepting <code><phrase role="identifier">pred</phrase></code>
- is shorthand for:
- <programlisting><phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">pred</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase role="identifier">timeout</phrase> <phrase role="special">==</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">pred</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">return</phrase> <phrase role="keyword">true</phrase><phrase role="special">;</phrase>
- </programlisting>
- That is, even if <code><phrase role="identifier">wait_until</phrase><phrase
- role="special">()</phrase></code> times out, it can still return <code><phrase
- role="keyword">true</phrase></code> if <code><phrase role="identifier">pred</phrase><phrase
- role="special">()</phrase></code> returns <code><phrase role="keyword">true</phrase></code>
- at that time.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postcondition:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lk</phrase></code> is locked by the
- current fiber.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">fiber_error</phrase></code> if an error
- occurs or timeout-related exceptions.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- The overload without <code><phrase role="identifier">pred</phrase></code>
- returns <code><phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase
- role="identifier">no_timeout</phrase></code> if awakened by <code><phrase
- role="identifier">notify_one</phrase><phrase role="special">()</phrase></code>
- or <code><phrase role="identifier">notify_all</phrase><phrase role="special">()</phrase></code>,
- or <code><phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase
- role="identifier">timeout</phrase></code> if awakened because the system
- time is past <code><phrase role="identifier">abs_time</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- The overload accepting <code><phrase role="identifier">pred</phrase></code>
- returns <code><phrase role="keyword">false</phrase></code> if the call
- is returning because the time specified by <code><phrase role="identifier">abs_time</phrase></code>
- was reached and the predicate returns <code><phrase role="keyword">false</phrase></code>,
- <code><phrase role="keyword">true</phrase></code> otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- See <emphasis role="bold">Note</emphasis> for <link linkend="condition_variable_wait"><code>condition_variable::wait()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="condition_variable_wait_for_bridgehead">
- <phrase id="condition_variable_wait_for"/>
- <link linkend="condition_variable_wait_for">Templated
- member function <code>wait_for</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">cv_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <phrase role="special">&</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">rel_time</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> typename <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Pred</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> std::unique_lock< mutex > <phrase role="special">&</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">rel_time</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">Pred</phrase> <phrase role="identifier">pred</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lk</phrase></code> is locked by the
- current fiber, and either no other fiber is currently waiting on <code><phrase
- role="special">*</phrase><phrase role="keyword">this</phrase></code>,
- or the execution of the <code><phrase role="identifier">mutex</phrase><phrase
- role="special">()</phrase></code> member function on the <code><phrase
- role="identifier">lk</phrase></code> objects supplied in the calls
- to <code><phrase role="identifier">wait</phrase></code>, <code><phrase
- role="identifier">wait_for</phrase></code> or <code><phrase role="identifier">wait_until</phrase></code>
- in all the fibers currently waiting on <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code> would return the same value as
- <code><phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
- role="identifier">mutex</phrase><phrase role="special">()</phrase></code>
- for this call to <code><phrase role="identifier">wait_for</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Atomically call <code><phrase role="identifier">lk</phrase><phrase
- role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase
- role="special">()</phrase></code> and blocks the current fiber. The
- fiber will unblock when notified by a call to <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">notify_one</phrase><phrase
- role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">notify_all</phrase><phrase
- role="special">()</phrase></code>, when a time interval equal to or
- greater than the specified <code><phrase role="identifier">rel_time</phrase></code>
- has elapsed. When the fiber is unblocked (for whatever reason), the
- lock is reacquired by invoking <code><phrase role="identifier">lk</phrase><phrase
- role="special">.</phrase><phrase role="identifier">lock</phrase><phrase
- role="special">()</phrase></code> before the call to <code><phrase
- role="identifier">wait</phrase></code> returns. The lock is also reacquired
- by invoking <code><phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase
- role="identifier">lock</phrase><phrase role="special">()</phrase></code>
- if the function exits with an exception. The <code><phrase role="identifier">wait_for</phrase><phrase
- role="special">()</phrase></code> member function accepting <code><phrase
- role="identifier">pred</phrase></code> is shorthand for:
- <programlisting><phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">pred</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase role="identifier">timeout</phrase> <phrase role="special">==</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="identifier">rel_time</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">pred</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">return</phrase> <phrase role="keyword">true</phrase><phrase role="special">;</phrase>
- </programlisting>
- (except of course that <code><phrase role="identifier">rel_time</phrase></code>
- is adjusted for each iteration). The point is that, even if <code><phrase
- role="identifier">wait_for</phrase><phrase role="special">()</phrase></code>
- times out, it can still return <code><phrase role="keyword">true</phrase></code>
- if <code><phrase role="identifier">pred</phrase><phrase role="special">()</phrase></code>
- returns <code><phrase role="keyword">true</phrase></code> at that time.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postcondition:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">lk</phrase></code> is locked by the
- current fiber.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">fiber_error</phrase></code> if an error
- occurs or timeout-related exceptions.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- The overload without <code><phrase role="identifier">pred</phrase></code>
- returns <code><phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase
- role="identifier">no_timeout</phrase></code> if awakened by <code><phrase
- role="identifier">notify_one</phrase><phrase role="special">()</phrase></code>
- or <code><phrase role="identifier">notify_all</phrase><phrase role="special">()</phrase></code>,
- or <code><phrase role="identifier">cv_status</phrase><phrase role="special">::</phrase><phrase
- role="identifier">timeout</phrase></code> if awakened because at least
- <code><phrase role="identifier">rel_time</phrase></code> has elapsed.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- The overload accepting <code><phrase role="identifier">pred</phrase></code>
- returns <code><phrase role="keyword">false</phrase></code> if the call
- is returning because at least <code><phrase role="identifier">rel_time</phrase></code>
- has elapsed and the predicate returns <code><phrase role="keyword">false</phrase></code>,
- <code><phrase role="keyword">true</phrase></code> otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- See <emphasis role="bold">Note</emphasis> for <link linkend="condition_variable_wait"><code>condition_variable::wait()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section id="fiber.synchronization.barriers">
- <title><link linkend="fiber.synchronization.barriers">Barriers</link></title>
- <para>
- A barrier is a concept also known as a <emphasis>rendezvous</emphasis>, it
- is a synchronization point between multiple contexts of execution (fibers).
- The barrier is configured for a particular number of fibers (<code><phrase
- role="identifier">n</phrase></code>), and as fibers reach the barrier they
- must wait until all <code><phrase role="identifier">n</phrase></code> fibers
- have arrived. Once the <code><phrase role="identifier">n</phrase></code>-th
- fiber has reached the barrier, all the waiting fibers can proceed, and the
- barrier is reset.
- </para>
- <para>
- The fact that the barrier automatically resets is significant. Consider a
- case in which you launch some number of fibers and want to wait only until
- the first of them has completed. You might be tempted to use a <code><phrase
- role="identifier">barrier</phrase><phrase role="special">(</phrase><phrase
- role="number">2</phrase><phrase role="special">)</phrase></code> as the synchronization
- mechanism, making each new fiber call its <link linkend="barrier_wait"><code>barrier::wait()</code></link> method,
- then calling <code><phrase role="identifier">wait</phrase><phrase role="special">()</phrase></code>
- in the launching fiber to wait until the first other fiber completes.
- </para>
- <para>
- That will in fact unblock the launching fiber. The unfortunate part is that
- it will continue blocking the <emphasis>remaining</emphasis> fibers.
- </para>
- <para>
- Consider the following scenario:
- </para>
- <orderedlist>
- <listitem>
- <simpara>
- Fiber <quote>main</quote> launches fibers A, B, C and D, then calls
- <code><phrase role="identifier">barrier</phrase><phrase role="special">::</phrase><phrase
- role="identifier">wait</phrase><phrase role="special">()</phrase></code>.
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- Fiber C finishes first and likewise calls <code><phrase role="identifier">barrier</phrase><phrase
- role="special">::</phrase><phrase role="identifier">wait</phrase><phrase
- role="special">()</phrase></code>.
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- Fiber <quote>main</quote> is unblocked, as desired.
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- Fiber B calls <code><phrase role="identifier">barrier</phrase><phrase
- role="special">::</phrase><phrase role="identifier">wait</phrase><phrase
- role="special">()</phrase></code>. Fiber B is <emphasis>blocked!</emphasis>
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- Fiber A calls <code><phrase role="identifier">barrier</phrase><phrase
- role="special">::</phrase><phrase role="identifier">wait</phrase><phrase
- role="special">()</phrase></code>. Fibers A and B are unblocked.
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- Fiber D calls <code><phrase role="identifier">barrier</phrase><phrase
- role="special">::</phrase><phrase role="identifier">wait</phrase><phrase
- role="special">()</phrase></code>. Fiber D is blocked indefinitely.
- </simpara>
- </listitem>
- </orderedlist>
- <para>
- (See also <link linkend="wait_first_simple_section">when_any, simple completion</link>.)
- </para>
- <note>
- <para>
- It is unwise to tie the lifespan of a barrier to any one of its participating
- fibers. Although conceptually all waiting fibers awaken <quote>simultaneously,</quote>
- because of the nature of fibers, in practice they will awaken one by one
- in indeterminate order.<footnote id="fiber.synchronization.barriers.f0">
- <para>
- The current implementation wakes fibers in FIFO order: the first to call
- <code><phrase role="identifier">wait</phrase><phrase role="special">()</phrase></code>
- wakes first, and so forth. But it is perilous to rely on the order in
- which the various fibers will reach the <code><phrase role="identifier">wait</phrase><phrase
- role="special">()</phrase></code> call.
- </para>
- </footnote> The rest of the waiting fibers will still be blocked in <code><phrase
- role="identifier">wait</phrase><phrase role="special">()</phrase></code>,
- which must, before returning, access data members in the barrier object.
- </para>
- </note>
- <para>
- <bridgehead renderas="sect4" id="class_barrier_bridgehead">
- <phrase id="class_barrier"/>
- <link linkend="class_barrier">Class <code>barrier</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">barrier</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">barrier</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="keyword">explicit</phrase> <phrase role="identifier">barrier</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">barrier</phrase><phrase role="special">(</phrase> <phrase role="identifier">barrier</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">barrier</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">barrier</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">wait</phrase><phrase role="special">();</phrase>
- <phrase role="special">};</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <para>
- Instances of <link linkend="class_barrier"><code>barrier</code></link> are not copyable or movable.
- </para>
- <bridgehead renderas="sect4" id="fiber.synchronization.barriers.h0">
- <phrase id="fiber.synchronization.barriers.constructor"/><link linkend="fiber.synchronization.barriers.constructor">Constructor</link>
- </bridgehead>
- <programlisting><phrase role="keyword">explicit</phrase> <phrase role="identifier">barrier</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">initial</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Construct a barrier for <code><phrase role="identifier">initial</phrase></code>
- fibers.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">fiber_error</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Error Conditions:</term>
- <listitem>
- <para>
- <emphasis role="bold">invalid_argument</emphasis>: if <code><phrase
- role="identifier">initial</phrase></code> is zero.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="barrier_wait_bridgehead">
- <phrase id="barrier_wait"/>
- <link linkend="barrier_wait">Member function <code>wait</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">wait</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Block until <code><phrase role="identifier">initial</phrase></code>
- fibers have called <code><phrase role="identifier">wait</phrase></code>
- on <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
- When the <code><phrase role="identifier">initial</phrase></code>-th
- fiber calls <code><phrase role="identifier">wait</phrase></code>, all
- waiting fibers are unblocked, and the barrier is reset.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> for exactly one fiber
- from each batch of waiting fibers, <code><phrase role="keyword">false</phrase></code>
- otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">fiber_error</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section id="fiber.synchronization.channels">
- <title><link linkend="fiber.synchronization.channels">Channels</link></title>
- <para>
- A channel is a model to communicate and synchronize <code><phrase role="identifier">Threads</phrase>
- <phrase role="identifier">of</phrase> <phrase role="identifier">Execution</phrase></code>
- <footnote id="fiber.synchronization.channels.f0">
- <para>
- The smallest ordered sequence of instructions that can be managed independently
- by a scheduler is called a <code><phrase role="identifier">Thread</phrase>
- <phrase role="identifier">of</phrase> <phrase role="identifier">Execution</phrase></code>.
- </para>
- </footnote> via message passing.
- </para>
- <anchor id="class_channel_op_status"/>
- <bridgehead renderas="sect4" id="fiber.synchronization.channels.h0">
- <phrase id="fiber.synchronization.channels.enumeration__code__phrase_role__identifier__channel_op_status__phrase___code_"/><link
- linkend="fiber.synchronization.channels.enumeration__code__phrase_role__identifier__channel_op_status__phrase___code_">Enumeration
- <code><phrase role="identifier">channel_op_status</phrase></code></link>
- </bridgehead>
- <para>
- channel operations return the state of the channel.
- </para>
- <programlisting><phrase role="keyword">enum</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">channel_op_status</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">success</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">empty</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">full</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">closed</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">timeout</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- <bridgehead renderas="sect4" id="fiber.synchronization.channels.h1">
- <phrase id="fiber.synchronization.channels._code__phrase_role__identifier__success__phrase___code_"/><link
- linkend="fiber.synchronization.channels._code__phrase_role__identifier__success__phrase___code_"><code><phrase
- role="identifier">success</phrase></code></link>
- </bridgehead>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Operation was successful.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect4" id="fiber.synchronization.channels.h2">
- <phrase id="fiber.synchronization.channels._code__phrase_role__identifier__empty__phrase___code_"/><link
- linkend="fiber.synchronization.channels._code__phrase_role__identifier__empty__phrase___code_"><code><phrase
- role="identifier">empty</phrase></code></link>
- </bridgehead>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- channel is empty, operation failed.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect4" id="fiber.synchronization.channels.h3">
- <phrase id="fiber.synchronization.channels._code__phrase_role__identifier__full__phrase___code_"/><link
- linkend="fiber.synchronization.channels._code__phrase_role__identifier__full__phrase___code_"><code><phrase
- role="identifier">full</phrase></code></link>
- </bridgehead>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- channel is full, operation failed.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect4" id="fiber.synchronization.channels.h4">
- <phrase id="fiber.synchronization.channels._code__phrase_role__identifier__closed__phrase___code_"/><link
- linkend="fiber.synchronization.channels._code__phrase_role__identifier__closed__phrase___code_"><code><phrase
- role="identifier">closed</phrase></code></link>
- </bridgehead>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- channel is closed, operation failed.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect4" id="fiber.synchronization.channels.h5">
- <phrase id="fiber.synchronization.channels._code__phrase_role__identifier__timeout__phrase___code_"/><link
- linkend="fiber.synchronization.channels._code__phrase_role__identifier__timeout__phrase___code_"><code><phrase
- role="identifier">timeout</phrase></code></link>
- </bridgehead>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- The operation did not become ready before specified timeout elapsed.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <section id="fiber.synchronization.channels.buffered_channel">
- <title><link linkend="fiber.synchronization.channels.buffered_channel">Buffered
- Channel</link></title>
- <para>
- <emphasis role="bold">Boost.Fiber</emphasis> provides a bounded, buffered
- channel (MPMC queue) suitable to synchonize fibers (running on same or
- different threads) via asynchronouss message passing.
- </para>
- <programlisting><phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="keyword">int</phrase> <phrase role="special">></phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">send</phrase><phrase role="special">(</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special"><</phrase> <phrase role="number">5</phrase><phrase role="special">;</phrase> <phrase role="special">++</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">i</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">close</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">recv</phrase><phrase role="special">(</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">i</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">channel_op_status</phrase><phrase role="special">::</phrase><phrase role="identifier">success</phrase> <phrase role="special">==</phrase> <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">pop</phrase><phrase role="special">(</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"received "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">i</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">channel_t</phrase> <phrase role="identifier">chan</phrase><phrase role="special">{</phrase> <phrase role="number">2</phrase> <phrase role="special">};</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f1</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">bind</phrase><phrase role="special">(</phrase> <phrase role="identifier">send</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ref</phrase><phrase role="special">(</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f2</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">bind</phrase><phrase role="special">(</phrase> <phrase role="identifier">recv</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ref</phrase><phrase role="special">(</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">f1</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">f2</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
- </programlisting>
- <para>
- Class <code><phrase role="identifier">buffered_channel</phrase></code>
- supports range-for syntax:
- </para>
- <programlisting><phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="keyword">int</phrase> <phrase role="special">></phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">foo</phrase><phrase role="special">(</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">2</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">3</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">5</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">8</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">12</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">close</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">bar</phrase><phrase role="special">(</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">unsigned</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">value</phrase> <phrase role="special">:</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">value</phrase> <phrase role="special"><<</phrase> <phrase role="string">" "</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- <para>
- <bridgehead renderas="sect4" id="class_buffered_channel_bridgehead">
- <phrase id="class_buffered_channel"/>
- <link linkend="class_buffered_channel">Template
- <code>buffered_channel<></code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">buffered_channel</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">T</phrase> <phrase role="identifier">value_type</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">iterator</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">explicit</phrase> <phrase role="identifier">buffered_channel</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">capacity</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">buffered_channel</phrase><phrase role="special">(</phrase> <phrase role="identifier">buffered_channel</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">buffered_channel</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">buffered_channel</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">close</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push_wait_for</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push_wait_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push_wait_until</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push_wait_until</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">value_type</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">try_push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">try_push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">value_type</phrase> <phrase role="identifier">value_pop</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop_wait_for</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">value_type</phrase> <phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop_wait_until</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">value_type</phrase> <phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">try_pop</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
- <phrase role="special">};</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">>::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">begin</phrase><phrase role="special">(</phrase> <phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">chan</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">>::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">end</phrase><phrase role="special">(</phrase> <phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">chan</phrase><phrase role="special">);</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <bridgehead renderas="sect5" id="fiber.synchronization.channels.buffered_channel.h0">
- <phrase id="fiber.synchronization.channels.buffered_channel.constructor"/><link
- linkend="fiber.synchronization.channels.buffered_channel.constructor">Constructor</link>
- </bridgehead>
- <programlisting><phrase role="keyword">explicit</phrase> <phrase role="identifier">buffered_channel</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">capacity</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Preconditions:</term>
- <listitem>
- <para>
- <code><phrase role="number">2</phrase><phrase role="special"><=</phrase><phrase
- role="identifier">capacity</phrase> <phrase role="special">&&</phrase>
- <phrase role="number">0</phrase><phrase role="special">==(</phrase><phrase
- role="identifier">capacity</phrase> <phrase role="special">&</phrase>
- <phrase role="special">(</phrase><phrase role="identifier">capacity</phrase><phrase
- role="special">-</phrase><phrase role="number">1</phrase><phrase
- role="special">))</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- The constructor constructs an object of class <code><phrase role="identifier">buffered_channel</phrase></code>
- with an internal buffer of size <code><phrase role="identifier">capacity</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">fiber_error</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Error Conditions:</term>
- <listitem>
- <para>
- <emphasis role="bold">invalid_argument</emphasis>: if <code><phrase
- role="number">0</phrase><phrase role="special">==</phrase><phrase
- role="identifier">capacity</phrase> <phrase role="special">||</phrase>
- <phrase role="number">0</phrase><phrase role="special">!=(</phrase><phrase
- role="identifier">capacity</phrase> <phrase role="special">&</phrase>
- <phrase role="special">(</phrase><phrase role="identifier">capacity</phrase><phrase
- role="special">-</phrase><phrase role="number">1</phrase><phrase
- role="special">))</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Notes:</term>
- <listitem>
- <para>
- A <code><phrase role="identifier">push</phrase><phrase role="special">()</phrase></code>,
- <code><phrase role="identifier">push_wait_for</phrase><phrase role="special">()</phrase></code>
- or <code><phrase role="identifier">push_wait_until</phrase><phrase
- role="special">()</phrase></code> will not block until the number
- of values in the channel becomes equal to <code><phrase role="identifier">capacity</phrase></code>.
- The channel can hold only <code><phrase role="identifier">capacity</phrase>
- <phrase role="special">-</phrase> <phrase role="number">1</phrase></code>
- elements, otherwise it is considered to be full.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="buffered_channel_close_bridgehead">
- <phrase id="buffered_channel_close"/>
- <link linkend="buffered_channel_close">Member
- function <code>close</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">close</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Deactivates the channel. No values can be put after calling <code><phrase
- role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">close</phrase><phrase role="special">()</phrase></code>.
- Fibers blocked in <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">pop</phrase><phrase
- role="special">()</phrase></code>, <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">pop_wait_for</phrase><phrase
- role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">pop_wait_until</phrase><phrase
- role="special">()</phrase></code> will return <code><phrase role="identifier">closed</phrase></code>.
- Fibers blocked in <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">value_pop</phrase><phrase
- role="special">()</phrase></code> will receive an exception.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">close</phrase><phrase role="special">()</phrase></code>
- is like closing a pipe. It informs waiting consumers that no more
- values will arrive.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="buffered_channel_push_bridgehead">
- <phrase id="buffered_channel_push"/>
- <link linkend="buffered_channel_push">Member
- function <code>push</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- If channel is closed, returns <code><phrase role="identifier">closed</phrase></code>.
- Otherwise enqueues the value in the channel, wakes up a fiber blocked
- on <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">pop</phrase><phrase role="special">()</phrase></code>,
- <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">value_pop</phrase><phrase role="special">()</phrase></code>,
- <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">pop_wait_for</phrase><phrase role="special">()</phrase></code>
- or <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">pop_wait_until</phrase><phrase role="special">()</phrase></code>
- and returns <code><phrase role="identifier">success</phrase></code>.
- If the channel is full, the fiber is blocked.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Exceptions thrown by copy- or move-operations.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="buffered_channel_try_push_bridgehead">
- <phrase id="buffered_channel_try_push"/>
- <link linkend="buffered_channel_try_push">Member
- function <code>try_push</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">try_push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">try_push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- If channel is closed, returns <code><phrase role="identifier">closed</phrase></code>.
- Otherwise enqueues the value in the channel, wakes up a fiber blocked
- on <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">pop</phrase><phrase role="special">()</phrase></code>,
- <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">value_pop</phrase><phrase role="special">()</phrase></code>,
- <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">pop_wait_for</phrase><phrase role="special">()</phrase></code>
- or <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">pop_wait_until</phrase><phrase role="special">()</phrase></code>
- and returns <code><phrase role="identifier">success</phrase></code>.
- If the channel is full, it doesn't block and returns <code><phrase
- role="identifier">full</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Exceptions thrown by copy- or move-operations.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="buffered_channel_pop_bridgehead">
- <phrase id="buffered_channel_pop"/>
- <link linkend="buffered_channel_pop">Member
- function <code>pop</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Dequeues a value from the channel. If the channel is empty, the fiber
- gets suspended until at least one new item is <code><phrase role="identifier">push</phrase><phrase
- role="special">()</phrase></code>ed (return value <code><phrase role="identifier">success</phrase></code>
- and <code><phrase role="identifier">va</phrase></code> contains dequeued
- value) or the channel gets <code><phrase role="identifier">close</phrase><phrase
- role="special">()</phrase></code>d (return value <code><phrase role="identifier">closed</phrase></code>).
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Exceptions thrown by copy- or move-operations.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="buffered_channel_value_pop_bridgehead">
- <phrase id="buffered_channel_value_pop"/>
- <link linkend="buffered_channel_value_pop">Member
- function <code>value_pop</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">value_type</phrase> <phrase role="identifier">value_pop</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Dequeues a value from the channel. If the channel is empty, the fiber
- gets suspended until at least one new item is <code><phrase role="identifier">push</phrase><phrase
- role="special">()</phrase></code>ed or the channel gets <code><phrase
- role="identifier">close</phrase><phrase role="special">()</phrase></code>d
- (which throws an exception).
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">fiber_error</phrase></code> if <code><phrase
- role="special">*</phrase><phrase role="keyword">this</phrase></code>
- is closed or by copy- or move-operations.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Error conditions:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">errc</phrase><phrase role="special">::</phrase><phrase
- role="identifier">operation_not_permitted</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="buffered_channel_try_pop_bridgehead">
- <phrase id="buffered_channel_try_pop"/>
- <link linkend="buffered_channel_try_pop">Member
- function <code>try_pop</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">try_pop</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- If channel is empty, returns <code><phrase role="identifier">empty</phrase></code>.
- If channel is closed, returns <code><phrase role="identifier">closed</phrase></code>.
- Otherwise it returns <code><phrase role="identifier">success</phrase></code>
- and <code><phrase role="identifier">va</phrase></code> contains the
- dequeued value.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Exceptions thrown by copy- or move-operations.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="buffered_channel_pop_wait_for_bridgehead">
- <phrase id="buffered_channel_pop_wait_for"/>
- <link linkend="buffered_channel_pop_wait_for">Member
- function <code>pop_wait_for</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop_wait_for</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">value_type</phrase> <phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">)</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Accepts <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase
- role="identifier">duration</phrase></code> and internally computes
- a timeout time as (system time + <code><phrase role="identifier">timeout_duration</phrase></code>).
- If channel is not empty, immediately dequeues a value from the channel.
- Otherwise the fiber gets suspended until at least one new item is
- <code><phrase role="identifier">push</phrase><phrase role="special">()</phrase></code>ed
- (return value <code><phrase role="identifier">success</phrase></code>
- and <code><phrase role="identifier">va</phrase></code> contains dequeued
- value), or the channel gets <code><phrase role="identifier">close</phrase><phrase
- role="special">()</phrase></code>d (return value <code><phrase role="identifier">closed</phrase></code>),
- or the system time reaches the computed timeout time (return value
- <code><phrase role="identifier">timeout</phrase></code>).
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- timeout-related exceptions or by copy- or move-operations.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="buffered_channel_pop_wait_until_bridgehead">
- <phrase id="buffered_channel_pop_wait_until"/>
- <link linkend="buffered_channel_pop_wait_until">Member
- function <code>pop_wait_until</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop_wait_until</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">value_type</phrase> <phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">)</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Accepts a <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase
- role="identifier">time_point</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase></code>.
- If channel is not empty, immediately dequeues a value from the channel.
- Otherwise the fiber gets suspended until at least one new item is
- <code><phrase role="identifier">push</phrase><phrase role="special">()</phrase></code>ed
- (return value <code><phrase role="identifier">success</phrase></code>
- and <code><phrase role="identifier">va</phrase></code> contains dequeued
- value), or the channel gets <code><phrase role="identifier">close</phrase><phrase
- role="special">()</phrase></code>d (return value <code><phrase role="identifier">closed</phrase></code>),
- or the system time reaches the passed <code><phrase role="identifier">time_point</phrase></code>
- (return value <code><phrase role="identifier">timeout</phrase></code>).
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- timeout-related exceptions or by copy- or move-operations.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect5" id="fiber.synchronization.channels.buffered_channel.h1">
- <phrase id="fiber.synchronization.channels.buffered_channel.non_member_function__code__phrase_role__identifier__begin__phrase__phrase_role__special_____phrase___phrase_role__identifier__buffered_channel__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__t__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_"/><link
- linkend="fiber.synchronization.channels.buffered_channel.non_member_function__code__phrase_role__identifier__begin__phrase__phrase_role__special_____phrase___phrase_role__identifier__buffered_channel__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__t__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_">Non-member
- function <code><phrase role="identifier">begin</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
- <phrase role="special">&)</phrase></code></link>
- </bridgehead>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">>::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">begin</phrase><phrase role="special">(</phrase> <phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">&);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- Returns a range-iterator (input-iterator).
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect5" id="fiber.synchronization.channels.buffered_channel.h2">
- <phrase id="fiber.synchronization.channels.buffered_channel.non_member_function__code__phrase_role__identifier__end__phrase__phrase_role__special_____phrase___phrase_role__identifier__buffered_channel__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__t__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_"/><link
- linkend="fiber.synchronization.channels.buffered_channel.non_member_function__code__phrase_role__identifier__end__phrase__phrase_role__special_____phrase___phrase_role__identifier__buffered_channel__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__t__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_">Non-member
- function <code><phrase role="identifier">end</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
- <phrase role="special">&)</phrase></code></link>
- </bridgehead>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">>::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">end</phrase><phrase role="special">(</phrase> <phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">&);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- Returns an end range-iterator (input-iterator).
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section id="fiber.synchronization.channels.unbuffered_channel">
- <title><link linkend="fiber.synchronization.channels.unbuffered_channel">Unbuffered
- Channel</link></title>
- <para>
- <emphasis role="bold">Boost.Fiber</emphasis> provides template <code><phrase
- role="identifier">unbuffered_channel</phrase></code> suitable to synchonize
- fibers (running on same or different threads) via synchronous message passing.
- A fiber waiting to consume an value will block until the value is produced.
- If a fiber attempts to send a value through an unbuffered channel and no
- fiber is waiting to receive the value, the channel will block the sending
- fiber.
- </para>
- <para>
- The unbuffered channel acts as an <code><phrase role="identifier">rendezvous</phrase>
- <phrase role="identifier">point</phrase></code>.
- </para>
- <programlisting><phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase> <phrase role="keyword">int</phrase> <phrase role="special">></phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">send</phrase><phrase role="special">(</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special"><</phrase> <phrase role="number">5</phrase><phrase role="special">;</phrase> <phrase role="special">++</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">i</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">close</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">recv</phrase><phrase role="special">(</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">i</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">channel_op_status</phrase><phrase role="special">::</phrase><phrase role="identifier">success</phrase> <phrase role="special">==</phrase> <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">pop</phrase><phrase role="special">(</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"received "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">i</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">channel_t</phrase> <phrase role="identifier">chan</phrase><phrase role="special">{</phrase> <phrase role="number">1</phrase> <phrase role="special">};</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f1</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">bind</phrase><phrase role="special">(</phrase> <phrase role="identifier">send</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ref</phrase><phrase role="special">(</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f2</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">bind</phrase><phrase role="special">(</phrase> <phrase role="identifier">recv</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ref</phrase><phrase role="special">(</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">f1</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">f2</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
- </programlisting>
- <para>
- Range-for syntax is supported:
- </para>
- <programlisting><phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase> <phrase role="keyword">int</phrase> <phrase role="special">></phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">foo</phrase><phrase role="special">(</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">2</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">3</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">5</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">8</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="number">12</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">.</phrase><phrase role="identifier">close</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">bar</phrase><phrase role="special">(</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">&</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">unsigned</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">value</phrase> <phrase role="special">:</phrase> <phrase role="identifier">chan</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">value</phrase> <phrase role="special"><<</phrase> <phrase role="string">" "</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- <para>
- <bridgehead renderas="sect4" id="class_unbuffered_channel_bridgehead">
- <phrase id="class_unbuffered_channel"/>
- <link linkend="class_unbuffered_channel">Template
- <code>unbuffered_channel<></code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">unbuffered_channel</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">unbuffered_channel</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">T</phrase> <phrase role="identifier">value_type</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">iterator</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">unbuffered_channel</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">unbuffered_channel</phrase><phrase role="special">(</phrase> <phrase role="identifier">unbuffered_channel</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">unbuffered_channel</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">unbuffered_channel</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">close</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push_wait_for</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push_wait_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push_wait_until</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push_wait_until</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">value_type</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">value_type</phrase> <phrase role="identifier">value_pop</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop_wait_for</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">value_type</phrase> <phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop_wait_until</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">value_type</phrase> <phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">);</phrase>
- <phrase role="special">};</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">>::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">begin</phrase><phrase role="special">(</phrase> <phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">chan</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">>::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">end</phrase><phrase role="special">(</phrase> <phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">chan</phrase><phrase role="special">);</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <bridgehead renderas="sect5" id="fiber.synchronization.channels.unbuffered_channel.h0">
- <phrase id="fiber.synchronization.channels.unbuffered_channel.constructor"/><link
- linkend="fiber.synchronization.channels.unbuffered_channel.constructor">Constructor</link>
- </bridgehead>
- <programlisting><phrase role="identifier">unbuffered_channel</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- The constructor constructs an object of class <code><phrase role="identifier">unbuffered_channel</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="unbuffered_channel_close_bridgehead">
- <phrase id="unbuffered_channel_close"/>
- <link linkend="unbuffered_channel_close">Member
- function <code>close</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">close</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Deactivates the channel. No values can be put after calling <code><phrase
- role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">close</phrase><phrase role="special">()</phrase></code>.
- Fibers blocked in <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">pop</phrase><phrase
- role="special">()</phrase></code>, <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">pop_wait_for</phrase><phrase
- role="special">()</phrase></code> or <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">pop_wait_until</phrase><phrase
- role="special">()</phrase></code> will return <code><phrase role="identifier">closed</phrase></code>.
- Fibers blocked in <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">value_pop</phrase><phrase
- role="special">()</phrase></code> will receive an exception.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">close</phrase><phrase role="special">()</phrase></code>
- is like closing a pipe. It informs waiting consumers that no more
- values will arrive.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="unbuffered_channel_push_bridgehead">
- <phrase id="unbuffered_channel_push"/>
- <link linkend="unbuffered_channel_push">Member
- function <code>push</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- If channel is closed, returns <code><phrase role="identifier">closed</phrase></code>.
- Otherwise enqueues the value in the channel, wakes up a fiber blocked
- on <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">pop</phrase><phrase role="special">()</phrase></code>,
- <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">value_pop</phrase><phrase role="special">()</phrase></code>,
- <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">pop_wait_for</phrase><phrase role="special">()</phrase></code>
- or <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">pop_wait_until</phrase><phrase role="special">()</phrase></code>
- and returns <code><phrase role="identifier">success</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Exceptions thrown by copy- or move-operations.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="unbuffered_channel_pop_bridgehead">
- <phrase id="unbuffered_channel_pop"/>
- <link linkend="unbuffered_channel_pop">Member
- function <code>pop</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_type</phrase> <phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Dequeues a value from the channel. If the channel is empty, the fiber
- gets suspended until at least one new item is <code><phrase role="identifier">push</phrase><phrase
- role="special">()</phrase></code>ed (return value <code><phrase role="identifier">success</phrase></code>
- and <code><phrase role="identifier">va</phrase></code> contains dequeued
- value) or the channel gets <code><phrase role="identifier">close</phrase><phrase
- role="special">()</phrase></code>d (return value <code><phrase role="identifier">closed</phrase></code>).
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Exceptions thrown by copy- or move-operations.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="unbuffered_channel_value_pop_bridgehead">
- <phrase id="unbuffered_channel_value_pop"/>
- <link linkend="unbuffered_channel_value_pop">Member
- function <code>value_pop</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">value_type</phrase> <phrase role="identifier">value_pop</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Dequeues a value from the channel. If the channel is empty, the fiber
- gets suspended until at least one new item is <code><phrase role="identifier">push</phrase><phrase
- role="special">()</phrase></code>ed or the channel gets <code><phrase
- role="identifier">close</phrase><phrase role="special">()</phrase></code>d
- (which throws an exception).
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">fiber_error</phrase></code> if <code><phrase
- role="special">*</phrase><phrase role="keyword">this</phrase></code>
- is closed or by copy- or move-operations.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Error conditions:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">errc</phrase><phrase role="special">::</phrase><phrase
- role="identifier">operation_not_permitted</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="unbuffered_channel_pop_wait_for_bridgehead">
- <phrase id="unbuffered_channel_pop_wait_for"/>
- <link linkend="unbuffered_channel_pop_wait_for">Member
- function <code>pop_wait_for</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop_wait_for</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">value_type</phrase> <phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">)</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Accepts <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase
- role="identifier">duration</phrase></code> and internally computes
- a timeout time as (system time + <code><phrase role="identifier">timeout_duration</phrase></code>).
- If channel is not empty, immediately dequeues a value from the channel.
- Otherwise the fiber gets suspended until at least one new item is
- <code><phrase role="identifier">push</phrase><phrase role="special">()</phrase></code>ed
- (return value <code><phrase role="identifier">success</phrase></code>
- and <code><phrase role="identifier">va</phrase></code> contains dequeued
- value), or the channel gets <code><phrase role="identifier">close</phrase><phrase
- role="special">()</phrase></code>d (return value <code><phrase role="identifier">closed</phrase></code>),
- or the system time reaches the computed timeout time (return value
- <code><phrase role="identifier">timeout</phrase></code>).
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- timeout-related exceptions or by copy- or move-operations.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="unbuffered_channel_pop_wait_until_bridgehead">
- <phrase id="unbuffered_channel_pop_wait_until"/>
- <link linkend="unbuffered_channel_pop_wait_until">Member
- function <code>pop_wait_until</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">channel_op_status</phrase> <phrase role="identifier">pop_wait_until</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">value_type</phrase> <phrase role="special">&</phrase> <phrase role="identifier">va</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">)</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Accepts a <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase
- role="identifier">time_point</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase></code>.
- If channel is not empty, immediately dequeues a value from the channel.
- Otherwise the fiber gets suspended until at least one new item is
- <code><phrase role="identifier">push</phrase><phrase role="special">()</phrase></code>ed
- (return value <code><phrase role="identifier">success</phrase></code>
- and <code><phrase role="identifier">va</phrase></code> contains dequeued
- value), or the channel gets <code><phrase role="identifier">close</phrase><phrase
- role="special">()</phrase></code>d (return value <code><phrase role="identifier">closed</phrase></code>),
- or the system time reaches the passed <code><phrase role="identifier">time_point</phrase></code>
- (return value <code><phrase role="identifier">timeout</phrase></code>).
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- timeout-related exceptions or by copy- or move-operations.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect5" id="fiber.synchronization.channels.unbuffered_channel.h1">
- <phrase id="fiber.synchronization.channels.unbuffered_channel.non_member_function__code__phrase_role__identifier__begin__phrase__phrase_role__special_____phrase___phrase_role__identifier__unbuffered_channel__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__t__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_"/><link
- linkend="fiber.synchronization.channels.unbuffered_channel.non_member_function__code__phrase_role__identifier__begin__phrase__phrase_role__special_____phrase___phrase_role__identifier__unbuffered_channel__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__t__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_">Non-member
- function <code><phrase role="identifier">begin</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
- <phrase role="special">&)</phrase></code></link>
- </bridgehead>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">>::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">begin</phrase><phrase role="special">(</phrase> <phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">&);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- Returns a range-iterator (input-iterator).
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect5" id="fiber.synchronization.channels.unbuffered_channel.h2">
- <phrase id="fiber.synchronization.channels.unbuffered_channel.non_member_function__code__phrase_role__identifier__end__phrase__phrase_role__special_____phrase___phrase_role__identifier__unbuffered_channel__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__t__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_"/><link
- linkend="fiber.synchronization.channels.unbuffered_channel.non_member_function__code__phrase_role__identifier__end__phrase__phrase_role__special_____phrase___phrase_role__identifier__unbuffered_channel__phrase__phrase_role__special___lt___phrase___phrase_role__identifier__t__phrase___phrase_role__special___gt___phrase___phrase_role__special___amp____phrase___code_">Non-member
- function <code><phrase role="identifier">end</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
- <phrase role="special">&)</phrase></code></link>
- </bridgehead>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">>::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">end</phrase><phrase role="special">(</phrase> <phrase role="identifier">unbuffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">&);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- Returns an end range-iterator (input-iterator).
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- </section>
- <section id="fiber.synchronization.futures">
- <title><link linkend="fiber.synchronization.futures">Futures</link></title>
- <bridgehead renderas="sect4" id="fiber.synchronization.futures.h0">
- <phrase id="fiber.synchronization.futures.overview"/><link linkend="fiber.synchronization.futures.overview">Overview</link>
- </bridgehead>
- <para>
- The futures library provides a means of handling asynchronous future values,
- whether those values are generated by another fiber, or on a single fiber
- in response to external stimuli, or on-demand.
- </para>
- <para>
- This is done through the provision of four class templates: <link linkend="class_future"><code>future<></code></link> and
- <link linkend="class_shared_future"><code>shared_future<></code></link> which are used to retrieve the asynchronous
- results, and <link linkend="class_promise"><code>promise<></code></link> and <link linkend="class_packaged_task"><code>packaged_task<></code></link> which
- are used to generate the asynchronous results.
- </para>
- <para>
- An instance of <link linkend="class_future"><code>future<></code></link> holds the one and only reference
- to a result. Ownership can be transferred between instances using the move
- constructor or move-assignment operator, but at most one instance holds a
- reference to a given asynchronous result. When the result is ready, it is
- returned from <link linkend="future_get"><code>future::get()</code></link> by rvalue-reference to allow the result
- to be moved or copied as appropriate for the type.
- </para>
- <para>
- On the other hand, many instances of <link linkend="class_shared_future"><code>shared_future<></code></link> may
- reference the same result. Instances can be freely copied and assigned, and
- <link linkend="shared_future_get"><code>shared_future::get()</code></link>
- returns a <code><phrase role="keyword">const</phrase></code>
- reference so that multiple calls to <link linkend="shared_future_get"><code>shared_future::get()</code></link>
- are
- safe. You can move an instance of <link linkend="class_future"><code>future<></code></link> into an instance
- of <link linkend="class_shared_future"><code>shared_future<></code></link>, thus transferring ownership
- of the associated asynchronous result, but not vice-versa.
- </para>
- <para>
- <link linkend="fibers_async"><code>fibers::async()</code></link> is a simple way of running asynchronous tasks.
- A call to <code><phrase role="identifier">async</phrase><phrase role="special">()</phrase></code>
- spawns a fiber and returns a <link linkend="class_future"><code>future<></code></link> that will deliver
- the result of the fiber function.
- </para>
- <bridgehead renderas="sect4" id="fiber.synchronization.futures.h1">
- <phrase id="fiber.synchronization.futures.creating_asynchronous_values"/><link
- linkend="fiber.synchronization.futures.creating_asynchronous_values">Creating
- asynchronous values</link>
- </bridgehead>
- <para>
- You can set the value in a future with either a <link linkend="class_promise"><code>promise<></code></link> or
- a <link linkend="class_packaged_task"><code>packaged_task<></code></link>. A <link linkend="class_packaged_task"><code>packaged_task<></code></link> is
- a callable object with <code><phrase role="keyword">void</phrase></code>
- return that wraps a function or callable object returning the specified type.
- When the <link linkend="class_packaged_task"><code>packaged_task<></code></link> is invoked, it invokes the
- contained function in turn, and populates a future with the contained function's
- return value. This is an answer to the perennial question: <quote>How do
- I return a value from a fiber?</quote> Package the function you wish to run
- as a <link linkend="class_packaged_task"><code>packaged_task<></code></link> and pass the packaged task to
- the fiber constructor. The future retrieved from the packaged task can then
- be used to obtain the return value. If the function throws an exception,
- that is stored in the future in place of the return value.
- </para>
- <programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">calculate_the_answer_to_life_the_universe_and_everything</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">return</phrase> <phrase role="number">42</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">packaged_task</phrase><phrase role="special"><</phrase><phrase role="keyword">int</phrase><phrase role="special">()></phrase> <phrase role="identifier">pt</phrase><phrase role="special">(</phrase><phrase role="identifier">calculate_the_answer_to_life_the_universe_and_everything</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special"><</phrase><phrase role="keyword">int</phrase><phrase role="special">></phrase> <phrase role="identifier">fi</phrase><phrase role="special">=</phrase><phrase role="identifier">pt</phrase><phrase role="special">.</phrase><phrase role="identifier">get_future</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase><phrase role="identifier">pt</phrase><phrase role="special">)).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase> <phrase role="comment">// launch task on a fiber</phrase>
- <phrase role="identifier">fi</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">();</phrase> <phrase role="comment">// wait for it to finish</phrase>
- <phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">fi</phrase><phrase role="special">.</phrase><phrase role="identifier">is_ready</phrase><phrase role="special">());</phrase>
- <phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">fi</phrase><phrase role="special">.</phrase><phrase role="identifier">has_value</phrase><phrase role="special">());</phrase>
- <phrase role="identifier">assert</phrase><phrase role="special">(!</phrase><phrase role="identifier">fi</phrase><phrase role="special">.</phrase><phrase role="identifier">has_exception</phrase><phrase role="special">());</phrase>
- <phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">fi</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">()==</phrase><phrase role="number">42</phrase><phrase role="special">);</phrase>
- </programlisting>
- <para>
- A <link linkend="class_promise"><code>promise<></code></link> is a bit more low level: it just provides explicit
- functions to store a value or an exception in the associated future. A promise
- can therefore be used where the value might come from more than one possible
- source.
- </para>
- <programlisting><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">promise</phrase><phrase role="special"><</phrase><phrase role="keyword">int</phrase><phrase role="special">></phrase> <phrase role="identifier">pi</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special"><</phrase><phrase role="keyword">int</phrase><phrase role="special">></phrase> <phrase role="identifier">fi</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">fi</phrase><phrase role="special">=</phrase><phrase role="identifier">pi</phrase><phrase role="special">.</phrase><phrase role="identifier">get_future</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">pi</phrase><phrase role="special">.</phrase><phrase role="identifier">set_value</phrase><phrase role="special">(</phrase><phrase role="number">42</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">fi</phrase><phrase role="special">.</phrase><phrase role="identifier">is_ready</phrase><phrase role="special">());</phrase>
- <phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">fi</phrase><phrase role="special">.</phrase><phrase role="identifier">has_value</phrase><phrase role="special">());</phrase>
- <phrase role="identifier">assert</phrase><phrase role="special">(!</phrase><phrase role="identifier">fi</phrase><phrase role="special">.</phrase><phrase role="identifier">has_exception</phrase><phrase role="special">());</phrase>
- <phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">fi</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">()==</phrase><phrase role="number">42</phrase><phrase role="special">);</phrase>
- </programlisting>
- <section id="fiber.synchronization.futures.future">
- <title><link linkend="fiber.synchronization.futures.future">Future</link></title>
- <para>
- A future provides a mechanism to access the result of an asynchronous operation.
- </para>
- <anchor id="shared_state"/>
- <bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h0">
- <phrase id="fiber.synchronization.futures.future.shared_state"/><link linkend="fiber.synchronization.futures.future.shared_state">shared
- state</link>
- </bridgehead>
- <para>
- Behind a <link linkend="class_promise"><code>promise<></code></link> and its <link linkend="class_future"><code>future<></code></link> lies
- an unspecified object called their <emphasis>shared state</emphasis>. The
- shared state is what will actually hold the async result (or the exception).
- </para>
- <para>
- The shared state is instantiated along with the <link linkend="class_promise"><code>promise<></code></link>.
- </para>
- <para>
- Aside from its originating <code><phrase role="identifier">promise</phrase><phrase
- role="special"><></phrase></code>, a <link linkend="class_future"><code>future<></code></link> holds
- a unique reference to a particular shared state. However, multiple <link linkend="class_shared_future"><code>shared_future<></code></link> instances
- can reference the same underlying shared state.
- </para>
- <para>
- As <link linkend="class_packaged_task"><code>packaged_task<></code></link> and <link linkend="fibers_async"><code>fibers::async()</code></link> are
- implemented using <link linkend="class_promise"><code>promise<></code></link>, discussions of shared state
- apply to them as well.
- </para>
- <anchor id="class_future_status"/>
- <bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h1">
- <phrase id="fiber.synchronization.futures.future.enumeration__code__phrase_role__identifier__future_status__phrase___code_"/><link
- linkend="fiber.synchronization.futures.future.enumeration__code__phrase_role__identifier__future_status__phrase___code_">Enumeration
- <code><phrase role="identifier">future_status</phrase></code></link>
- </bridgehead>
- <para>
- Timed wait-operations (<link linkend="future_wait_for"><code>future::wait_for()</code></link> and <link linkend="future_wait_until"><code>future::wait_until()</code></link>)
- return the state of the future.
- </para>
- <programlisting><phrase role="keyword">enum</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">future_status</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">ready</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">timeout</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">deferred</phrase> <phrase role="comment">// not supported yet</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- <bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h2">
- <phrase id="fiber.synchronization.futures.future._code__phrase_role__identifier__ready__phrase___code_"/><link
- linkend="fiber.synchronization.futures.future._code__phrase_role__identifier__ready__phrase___code_"><code><phrase
- role="identifier">ready</phrase></code></link>
- </bridgehead>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- The <link linkend="shared_state">shared state</link> is ready.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h3">
- <phrase id="fiber.synchronization.futures.future._code__phrase_role__identifier__timeout__phrase___code_"/><link
- linkend="fiber.synchronization.futures.future._code__phrase_role__identifier__timeout__phrase___code_"><code><phrase
- role="identifier">timeout</phrase></code></link>
- </bridgehead>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- The <link linkend="shared_state">shared state</link> did not become
- ready before timeout has passed.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <note>
- <para>
- Deferred futures are not supported.
- </para>
- </note>
- <para>
- <bridgehead renderas="sect4" id="class_future_bridgehead">
- <phrase id="class_future"/>
- <link linkend="class_future">Template <code>future<></code></link>
- </bridgehead>
- </para>
- <para>
- A <link linkend="class_future"><code>future<></code></link> contains a <link linkend="shared_state">shared
- state</link> which is not shared with any other future.
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">future</phrase><phrase role="special">/</phrase><phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">future</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">future</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">future</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">future</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">future</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">future</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">future</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">future</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="special">~</phrase><phrase role="identifier">future</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">valid</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">shared_future</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="identifier">share</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">R</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of generic future template</phrase>
- <phrase role="identifier">R</phrase> <phrase role="special">&</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of future< R & > template specialization</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of future< void > template specialization</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase> <phrase role="identifier">get_exception_ptr</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">future_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">future_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
- <phrase role="special">};</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h4">
- <phrase id="fiber.synchronization.futures.future.default_constructor"/><link
- linkend="fiber.synchronization.futures.future.default_constructor">Default
- constructor</link>
- </bridgehead>
- <programlisting><phrase role="identifier">future</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Creates a future with no <link linkend="shared_state">shared state</link>.
- After construction <code><phrase role="keyword">false</phrase> <phrase
- role="special">==</phrase> <phrase role="identifier">valid</phrase><phrase
- role="special">()</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h5">
- <phrase id="fiber.synchronization.futures.future.move_constructor"/><link
- linkend="fiber.synchronization.futures.future.move_constructor">Move constructor</link>
- </bridgehead>
- <programlisting><phrase role="identifier">future</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Constructs a future with the <link linkend="shared_state">shared
- state</link> of other. After construction <code><phrase role="keyword">false</phrase>
- <phrase role="special">==</phrase> <phrase role="identifier">other</phrase><phrase
- role="special">.</phrase><phrase role="identifier">valid</phrase><phrase
- role="special">()</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h6">
- <phrase id="fiber.synchronization.futures.future.destructor"/><link linkend="fiber.synchronization.futures.future.destructor">Destructor</link>
- </bridgehead>
- <programlisting><phrase role="special">~</phrase><phrase role="identifier">future</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Destroys the future; ownership is abandoned.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- <code>~future()</code> does <emphasis>not</emphasis> block the calling fiber.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- Consider a sequence such as:
- </para>
- <orderedlist>
- <listitem>
- <simpara>
- instantiate <link linkend="class_promise"><code>promise<></code></link>
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- obtain its <code><phrase role="identifier">future</phrase><phrase role="special"><></phrase></code>
- via <link linkend="promise_get_future"><code>promise::get_future()</code></link>
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- launch <link linkend="class_fiber"><code>fiber</code></link>, capturing <code><phrase role="identifier">promise</phrase><phrase
- role="special"><></phrase></code>
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- destroy <code><phrase role="identifier">future</phrase><phrase role="special"><></phrase></code>
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- call <link linkend="promise_set_value"><code>promise::set_value()</code></link>
- </simpara>
- </listitem>
- </orderedlist>
- <para>
- The final <code><phrase role="identifier">set_value</phrase><phrase role="special">()</phrase></code>
- call succeeds, but the value is silently discarded: no additional <code><phrase
- role="identifier">future</phrase><phrase role="special"><></phrase></code>
- can be obtained from that <code><phrase role="identifier">promise</phrase><phrase
- role="special"><></phrase></code>.
- </para>
- <para>
- <bridgehead renderas="sect4" id="future_operator_assign_bridgehead">
- <phrase id="future_operator_assign"/>
- <link linkend="future_operator_assign">Member
- function <code>operator=</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">future</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">future</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Moves the <link linkend="shared_state">shared state</link> of other
- to <code><phrase role="keyword">this</phrase></code>. After the assignment,
- <code><phrase role="keyword">false</phrase> <phrase role="special">==</phrase>
- <phrase role="identifier">other</phrase><phrase role="special">.</phrase><phrase
- role="identifier">valid</phrase><phrase role="special">()</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="future_valid_bridgehead">
- <phrase id="future_valid"/>
- <link linkend="future_valid">Member function <code>valid</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">valid</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Returns <code><phrase role="keyword">true</phrase></code> if future
- contains a <link linkend="shared_state">shared state</link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="future_share_bridgehead">
- <phrase id="future_share"/>
- <link linkend="future_share">Member function <code>share</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">shared_future</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="identifier">share</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Move the state to a <link linkend="class_shared_future"><code>shared_future<></code></link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- a <link linkend="class_shared_future"><code>shared_future<></code></link> containing the <link linkend="shared_state">shared
- state</link> formerly belonging to <code><phrase role="special">*</phrase><phrase
- role="keyword">this</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postcondition:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">false</phrase> <phrase role="special">==</phrase>
- <phrase role="identifier">valid</phrase><phrase role="special">()</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">future_error</phrase></code> with
- error condition <code><phrase role="identifier">future_errc</phrase><phrase
- role="special">::</phrase><phrase role="identifier">no_state</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="future_get_bridgehead">
- <phrase id="future_get"/>
- <link linkend="future_get">Member function <code>get</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">R</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of generic future template</phrase>
- <phrase role="identifier">R</phrase> <phrase role="special">&</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of future< R & > template specialization</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of future< void > template specialization</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase> <phrase role="special">==</phrase>
- <phrase role="identifier">valid</phrase><phrase role="special">()</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
- called. If <link linkend="promise_set_value"><code>promise::set_value()</code></link> is called, returns
- the value. If <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is called,
- throws the indicated exception.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postcondition:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">false</phrase> <phrase role="special">==</phrase>
- <phrase role="identifier">valid</phrase><phrase role="special">()</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">future_error</phrase></code> with
- error condition <code><phrase role="identifier">future_errc</phrase><phrase
- role="special">::</phrase><phrase role="identifier">no_state</phrase></code>,
- <code><phrase role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
- role="identifier">broken_promise</phrase></code>. Any exception passed
- to <code><phrase role="identifier">promise</phrase><phrase role="special">::</phrase><phrase
- role="identifier">set_exception</phrase><phrase role="special">()</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="future_get_exception_ptr_bridgehead">
- <phrase id="future_get_exception_ptr"/>
- <link linkend="future_get_exception_ptr">Member
- function <code>get_exception_ptr</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase> <phrase role="identifier">get_exception_ptr</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase> <phrase role="special">==</phrase>
- <phrase role="identifier">valid</phrase><phrase role="special">()</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
- called. If <code><phrase role="identifier">set_value</phrase><phrase
- role="special">()</phrase></code> is called, returns a default-constructed
- <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">exception_ptr</phrase></code>. If <code><phrase
- role="identifier">set_exception</phrase><phrase role="special">()</phrase></code>
- is called, returns the passed <code><phrase role="identifier">std</phrase><phrase
- role="special">::</phrase><phrase role="identifier">exception_ptr</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">future_error</phrase></code> with
- error condition <code><phrase role="identifier">future_errc</phrase><phrase
- role="special">::</phrase><phrase role="identifier">no_state</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">get_exception_ptr</phrase><phrase
- role="special">()</phrase></code> does <emphasis>not</emphasis> invalidate
- the <code>future</code>. After calling <code><phrase role="identifier">get_exception_ptr</phrase><phrase
- role="special">()</phrase></code>, you may still call <link linkend="future_get"><code>future::get()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="future_wait_bridgehead">
- <phrase id="future_wait"/>
- <link linkend="future_wait">Member function <code>wait</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
- called.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">future_error</phrase></code> with
- error condition <code><phrase role="identifier">future_errc</phrase><phrase
- role="special">::</phrase><phrase role="identifier">no_state</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="future_wait_for_bridgehead">
- <phrase id="future_wait_for"/>
- <link linkend="future_wait_for">Templated member
- function <code>wait_for</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">future_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
- called, or <code><phrase role="identifier">timeout_duration</phrase></code>
- has passed.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Result:</term>
- <listitem>
- <para>
- A <code><phrase role="identifier">future_status</phrase></code> is
- returned indicating the reason for returning.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">future_error</phrase></code> with
- error condition <code><phrase role="identifier">future_errc</phrase><phrase
- role="special">::</phrase><phrase role="identifier">no_state</phrase></code>
- or timeout-related exceptions.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="future_wait_until_bridgehead">
- <phrase id="future_wait_until"/>
- <link linkend="future_wait_until">Templated
- member function <code>wait_until</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">future_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
- called, or <code><phrase role="identifier">timeout_time</phrase></code>
- has passed.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Result:</term>
- <listitem>
- <para>
- A <code><phrase role="identifier">future_status</phrase></code> is
- returned indicating the reason for returning.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">future_error</phrase></code> with
- error condition <code><phrase role="identifier">future_errc</phrase><phrase
- role="special">::</phrase><phrase role="identifier">no_state</phrase></code>
- or timeout-related exceptions.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="class_shared_future_bridgehead">
- <phrase id="class_shared_future"/>
- <link linkend="class_shared_future">Template
- <code>shared_future<></code></link>
- </bridgehead>
- </para>
- <para>
- A <link linkend="class_shared_future"><code>shared_future<></code></link> contains a <link linkend="shared_state">shared
- state</link> which might be shared with other <link linkend="class_shared_future"><code>shared_future<></code></link> instances.
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">future</phrase><phrase role="special">/</phrase><phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">shared_future</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="special">~</phrase><phrase role="identifier">shared_future</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">shared_future</phrase><phrase role="special">(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">shared_future</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="special">&&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">shared_future</phrase><phrase role="special">(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">shared_future</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">shared_future</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="special">&&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">shared_future</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">valid</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">R</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of generic shared_future template</phrase>
- <phrase role="identifier">R</phrase> <phrase role="special">&</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of shared_future< R & > template specialization</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of shared_future< void > template specialization</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase> <phrase role="identifier">get_exception_ptr</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">future_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">future_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
- <phrase role="special">};</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h7">
- <phrase id="fiber.synchronization.futures.future.default_constructor0"/><link
- linkend="fiber.synchronization.futures.future.default_constructor0">Default
- constructor</link>
- </bridgehead>
- <programlisting><phrase role="identifier">shared_future</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Creates a shared_future with no <link linkend="shared_state">shared
- state</link>. After construction <code><phrase role="keyword">false</phrase>
- <phrase role="special">==</phrase> <phrase role="identifier">valid</phrase><phrase
- role="special">()</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h8">
- <phrase id="fiber.synchronization.futures.future.move_constructor0"/><link
- linkend="fiber.synchronization.futures.future.move_constructor0">Move constructor</link>
- </bridgehead>
- <programlisting><phrase role="identifier">shared_future</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="special">&&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">shared_future</phrase><phrase role="special">(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Constructs a shared_future with the <link linkend="shared_state">shared
- state</link> of other. After construction <code><phrase role="keyword">false</phrase>
- <phrase role="special">==</phrase> <phrase role="identifier">other</phrase><phrase
- role="special">.</phrase><phrase role="identifier">valid</phrase><phrase
- role="special">()</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h9">
- <phrase id="fiber.synchronization.futures.future.copy_constructor"/><link
- linkend="fiber.synchronization.futures.future.copy_constructor">Copy constructor</link>
- </bridgehead>
- <programlisting><phrase role="identifier">shared_future</phrase><phrase role="special">(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Constructs a shared_future with the <link linkend="shared_state">shared
- state</link> of other. After construction <code><phrase role="identifier">other</phrase><phrase
- role="special">.</phrase><phrase role="identifier">valid</phrase><phrase
- role="special">()</phrase></code> is unchanged.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect5" id="fiber.synchronization.futures.future.h10">
- <phrase id="fiber.synchronization.futures.future.destructor0"/><link linkend="fiber.synchronization.futures.future.destructor0">Destructor</link>
- </bridgehead>
- <programlisting><phrase role="special">~</phrase><phrase role="identifier">shared_future</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Destroys the shared_future; ownership is abandoned if not shared.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- <code>~shared_future()</code> does <emphasis>not</emphasis> block the calling fiber.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="shared_future_operator_assign_bridgehead">
- <phrase id="shared_future_operator_assign"/>
- <link linkend="shared_future_operator_assign">Member
- function <code>operator=</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">shared_future</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="special">&&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">shared_future</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">shared_future</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">shared_future</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Moves or copies the <link linkend="shared_state">shared state</link>
- of other to <code><phrase role="keyword">this</phrase></code>. After
- the assignment, the state of <code><phrase role="identifier">other</phrase><phrase
- role="special">.</phrase><phrase role="identifier">valid</phrase><phrase
- role="special">()</phrase></code> depends on which overload was invoked:
- unchanged for the overload accepting <code><phrase role="identifier">shared_future</phrase>
- <phrase role="keyword">const</phrase><phrase role="special">&</phrase></code>,
- otherwise <code><phrase role="keyword">false</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="shared_future_valid_bridgehead">
- <phrase id="shared_future_valid"/>
- <link linkend="shared_future_valid">Member
- function <code>valid</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">valid</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Returns <code><phrase role="keyword">true</phrase></code> if shared_future
- contains a <link linkend="shared_state">shared state</link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="shared_future_get_bridgehead">
- <phrase id="shared_future_get"/>
- <link linkend="shared_future_get">Member function
- <code>get</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">R</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of generic shared_future template</phrase>
- <phrase role="identifier">R</phrase> <phrase role="special">&</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of shared_future< R & > template specialization</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">get</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of shared_future< void > template specialization</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase> <phrase role="special">==</phrase>
- <phrase role="identifier">valid</phrase><phrase role="special">()</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
- called. If <link linkend="promise_set_value"><code>promise::set_value()</code></link> is called, returns
- the value. If <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is called,
- throws the indicated exception.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postcondition:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">false</phrase> <phrase role="special">==</phrase>
- <phrase role="identifier">valid</phrase><phrase role="special">()</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">future_error</phrase></code> with
- error condition <code><phrase role="identifier">future_errc</phrase><phrase
- role="special">::</phrase><phrase role="identifier">no_state</phrase></code>,
- <code><phrase role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
- role="identifier">broken_promise</phrase></code>. Any exception passed
- to <code><phrase role="identifier">promise</phrase><phrase role="special">::</phrase><phrase
- role="identifier">set_exception</phrase><phrase role="special">()</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="shared_future_get_exception_ptr_bridgehead">
- <phrase id="shared_future_get_exception_ptr"/>
- <link linkend="shared_future_get_exception_ptr">Member
- function <code>get_exception_ptr</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase> <phrase role="identifier">get_exception_ptr</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Precondition:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase> <phrase role="special">==</phrase>
- <phrase role="identifier">valid</phrase><phrase role="special">()</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
- called. If <code><phrase role="identifier">set_value</phrase><phrase
- role="special">()</phrase></code> is called, returns a default-constructed
- <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">exception_ptr</phrase></code>. If <code><phrase
- role="identifier">set_exception</phrase><phrase role="special">()</phrase></code>
- is called, returns the passed <code><phrase role="identifier">std</phrase><phrase
- role="special">::</phrase><phrase role="identifier">exception_ptr</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">future_error</phrase></code> with
- error condition <code><phrase role="identifier">future_errc</phrase><phrase
- role="special">::</phrase><phrase role="identifier">no_state</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">get_exception_ptr</phrase><phrase
- role="special">()</phrase></code> does <emphasis>not</emphasis> invalidate
- the <code>shared_future</code>. After calling <code><phrase role="identifier">get_exception_ptr</phrase><phrase
- role="special">()</phrase></code>, you may still call <link linkend="shared_future_get"><code>shared_future::get()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="shared_future_wait_bridgehead">
- <phrase id="shared_future_wait"/>
- <link linkend="shared_future_wait">Member
- function <code>wait</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
- called.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">future_error</phrase></code> with
- error condition <code><phrase role="identifier">future_errc</phrase><phrase
- role="special">::</phrase><phrase role="identifier">no_state</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="shared_future_wait_for_bridgehead">
- <phrase id="shared_future_wait_for"/>
- <link linkend="shared_future_wait_for">Templated
- member function <code>wait_for</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">future_status</phrase> <phrase role="identifier">wait_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">duration</phrase><phrase role="special"><</phrase> <phrase role="identifier">Rep</phrase><phrase role="special">,</phrase> <phrase role="identifier">Period</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_duration</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
- called, or <code><phrase role="identifier">timeout_duration</phrase></code>
- has passed.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Result:</term>
- <listitem>
- <para>
- A <code><phrase role="identifier">future_status</phrase></code> is
- returned indicating the reason for returning.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">future_error</phrase></code> with
- error condition <code><phrase role="identifier">future_errc</phrase><phrase
- role="special">::</phrase><phrase role="identifier">no_state</phrase></code>
- or timeout-related exceptions.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="shared_future_wait_until_bridgehead">
- <phrase id="shared_future_wait_until"/>
- <link linkend="shared_future_wait_until">Templated
- member function <code>wait_until</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">future_status</phrase> <phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special"><</phrase> <phrase role="identifier">Clock</phrase><phrase role="special">,</phrase> <phrase role="identifier">Duration</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">timeout_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Waits until <link linkend="promise_set_value"><code>promise::set_value()</code></link> or <link linkend="promise_set_exception"><code>promise::set_exception()</code></link> is
- called, or <code><phrase role="identifier">timeout_time</phrase></code>
- has passed.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Result:</term>
- <listitem>
- <para>
- A <code><phrase role="identifier">future_status</phrase></code> is
- returned indicating the reason for returning.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">future_error</phrase></code> with
- error condition <code><phrase role="identifier">future_errc</phrase><phrase
- role="special">::</phrase><phrase role="identifier">no_state</phrase></code>
- or timeout-related exceptions.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="fibers_async_bridgehead">
- <phrase id="fibers_async"/>
- <link linkend="fibers_async">Non-member function <code>fibers::async()</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">future</phrase><phrase role="special">/</phrase><phrase role="identifier">async</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Function</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">future</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of_t</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase>
- <phrase role="special">></phrase>
- <phrase role="special">></phrase>
- <phrase role="identifier">async</phrase><phrase role="special">(</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Function</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">future</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of_t</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase>
- <phrase role="special">></phrase>
- <phrase role="special">></phrase>
- <phrase role="identifier">async</phrase><phrase role="special">(</phrase> <link linkend="class_launch"><code><phrase role="identifier">launch</phrase></code></link> <phrase role="identifier">policy</phrase><phrase role="special">,</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Function</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">future</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of_t</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase>
- <phrase role="special">></phrase>
- <phrase role="special">></phrase>
- <phrase role="identifier">async</phrase><phrase role="special">(</phrase> <link linkend="class_launch"><code><phrase role="identifier">launch</phrase></code></link> <phrase role="identifier">policy</phrase><phrase role="special">,</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link> <phrase role="identifier">salloc</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">Function</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Allocator</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">Function</phrase><phrase role="special">,</phrase> <phrase role="keyword">class</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">future</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of_t</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase>
- <phrase role="special">></phrase>
- <phrase role="special">></phrase>
- <phrase role="identifier">async</phrase><phrase role="special">(</phrase> <link linkend="class_launch"><code><phrase role="identifier">launch</phrase></code></link> <phrase role="identifier">policy</phrase><phrase role="special">,</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link> <phrase role="identifier">salloc</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">Allocator</phrase> <phrase role="identifier">alloc</phrase><phrase role="special">,</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">fn</phrase><phrase role="special">,</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Executes <code><phrase role="identifier">fn</phrase></code> in a
- <link linkend="class_fiber"><code>fiber</code></link> and returns an associated <link linkend="class_future"><code>future<></code></link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Result:</term>
- <listitem>
- <para>
- <programlisting><phrase role="identifier">future</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of_t</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Function</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay_t</phrase><phrase role="special"><</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase>
- <phrase role="special">></phrase>
- <phrase role="special">></phrase></programlisting>
- representing the <link linkend="shared_state">shared state</link>
- associated with the asynchronous execution of <code><phrase role="identifier">fn</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">fiber_error</phrase></code> or <code><phrase
- role="identifier">future_error</phrase></code> if an error occurs.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Notes:</term>
- <listitem>
- <para>
- The overloads accepting <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">allocator_arg_t</phrase></code></ulink> use the
- passed <link linkend="stack_allocator_concept"><code><phrase role="identifier">StackAllocator</phrase></code></link>
- when constructing the launched <code><phrase role="identifier">fiber</phrase></code>.
- The overloads accepting <link linkend="class_launch"><code>launch</code></link> use the passed <code><phrase
- role="identifier">launch</phrase></code> when constructing the launched
- <code><phrase role="identifier">fiber</phrase></code>. The default
- <code><phrase role="identifier">launch</phrase></code> is <code><phrase
- role="identifier">post</phrase></code>, as for the <code><phrase
- role="identifier">fiber</phrase></code> constructor.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <note>
- <para>
- Deferred futures are not supported.
- </para>
- </note>
- </section>
- <section id="fiber.synchronization.futures.promise">
- <title><anchor id="class_promise"/><link linkend="fiber.synchronization.futures.promise">Template
- <code><phrase role="identifier">promise</phrase><phrase role="special"><></phrase></code></link></title>
- <para>
- A <link linkend="class_promise"><code>promise<></code></link> provides a mechanism to store a value (or
- exception) that can later be retrieved from the corresponding <link linkend="class_future"><code>future<></code></link> object.
- <code><phrase role="identifier">promise</phrase><phrase role="special"><></phrase></code>
- and <code><phrase role="identifier">future</phrase><phrase role="special"><></phrase></code>
- communicate via their underlying <link linkend="shared_state">shared state</link>.
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">future</phrase><phrase role="special">/</phrase><phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">promise</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">promise</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <ulink url="http://en.cppreference.com/w/cpp/concept/Allocator"><code><phrase role="identifier">Allocator</phrase></code></ulink> <phrase role="special">></phrase>
- <phrase role="identifier">promise</phrase><phrase role="special">(</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <phrase role="identifier">Allocator</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">promise</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase> <phrase role="special">&&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">promise</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">promise</phrase> <phrase role="special">&&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">promise</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">promise</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">promise</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="special">~</phrase><phrase role="identifier">promise</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase> <phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="identifier">get_future</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">R</phrase> <phrase role="keyword">const</phrase><phrase role="special">&);</phrase> <phrase role="comment">// member only of generic promise template</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&&);</phrase> <phrase role="comment">// member only of generic promise template</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&);</phrase> <phrase role="comment">// member only of promise< R & > template</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">set_value</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of promise< void > template</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">set_exception</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase> <phrase role="identifier">p</phrase><phrase role="special">);</phrase>
- <phrase role="special">};</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="special">&,</phrase> <phrase role="identifier">promise</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- <bridgehead renderas="sect5" id="fiber.synchronization.futures.promise.h0">
- <phrase id="fiber.synchronization.futures.promise.default_constructor"/><link
- linkend="fiber.synchronization.futures.promise.default_constructor">Default
- constructor</link>
- </bridgehead>
- <programlisting><phrase role="identifier">promise</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Creates a promise with an empty <link linkend="shared_state">shared
- state</link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Exceptions caused by memory allocation.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect5" id="fiber.synchronization.futures.promise.h1">
- <phrase id="fiber.synchronization.futures.promise.constructor"/><link linkend="fiber.synchronization.futures.promise.constructor">Constructor</link>
- </bridgehead>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <ulink url="http://en.cppreference.com/w/cpp/concept/Allocator"><code><phrase role="identifier">Allocator</phrase></code></ulink> <phrase role="special">></phrase>
- <phrase role="identifier">promise</phrase><phrase role="special">(</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <phrase role="identifier">Allocator</phrase> <phrase role="identifier">alloc</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Creates a promise with an empty <link linkend="shared_state">shared
- state</link> by using <code><phrase role="identifier">alloc</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Exceptions caused by memory allocation.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>See also:</term>
- <listitem>
- <para>
- <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">allocator_arg_t</phrase></code></ulink>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect5" id="fiber.synchronization.futures.promise.h2">
- <phrase id="fiber.synchronization.futures.promise.move_constructor"/><link
- linkend="fiber.synchronization.futures.promise.move_constructor">Move constructor</link>
- </bridgehead>
- <programlisting><phrase role="identifier">promise</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Creates a promise by moving the <link linkend="shared_state">shared
- state</link> from <code><phrase role="identifier">other</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postcondition:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">other</phrase></code> contains no
- valid shared state.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect5" id="fiber.synchronization.futures.promise.h3">
- <phrase id="fiber.synchronization.futures.promise.destructor"/><link linkend="fiber.synchronization.futures.promise.destructor">Destructor</link>
- </bridgehead>
- <programlisting><phrase role="special">~</phrase><phrase role="identifier">promise</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Destroys <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- and abandons the <link linkend="shared_state">shared state</link>
- if shared state is ready; otherwise stores <code><phrase role="identifier">future_error</phrase></code>
- with error condition <code><phrase role="identifier">future_errc</phrase><phrase
- role="special">::</phrase><phrase role="identifier">broken_promise</phrase></code>
- as if by <link linkend="promise_set_exception"><code>promise::set_exception()</code></link>: the shared
- state is set ready.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="promise_operator_assign_bridgehead">
- <phrase id="promise_operator_assign"/>
- <link linkend="promise_operator_assign">Member
- function <code>operator=</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">promise</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">promise</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Transfers the ownership of <link linkend="shared_state">shared state</link>
- to <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postcondition:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">other</phrase></code> contains no
- valid shared state.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="promise_swap_bridgehead">
- <phrase id="promise_swap"/>
- <link linkend="promise_swap">Member function <code>swap</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase> <phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Swaps the <link linkend="shared_state">shared state</link> between
- other and <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="promise_get_future_bridgehead">
- <phrase id="promise_get_future"/>
- <link linkend="promise_get_future">Member
- function <code>get_future</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="identifier">get_future</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- A <link linkend="class_future"><code>future<></code></link> with the same <link linkend="shared_state">shared
- state</link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">future_error</phrase></code> with
- <code><phrase role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
- role="identifier">future_already_retrieved</phrase></code> or <code><phrase
- role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
- role="identifier">no_state</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="promise_set_value_bridgehead">
- <phrase id="promise_set_value"/>
- <link linkend="promise_set_value">Member function
- <code>set_value</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">R</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">value</phrase><phrase role="special">);</phrase> <phrase role="comment">// member only of generic promise template</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">value</phrase><phrase role="special">);</phrase> <phrase role="comment">// member only of generic promise template</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">R</phrase> <phrase role="special">&</phrase> <phrase role="identifier">value</phrase><phrase role="special">);</phrase> <phrase role="comment">// member only of promise< R & > template</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">set_value</phrase><phrase role="special">();</phrase> <phrase role="comment">// member only of promise< void > template</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Store the result in the <link linkend="shared_state">shared state</link>
- and marks the state as ready.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">future_error</phrase></code> with
- <code><phrase role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
- role="identifier">future_already_satisfied</phrase></code> or <code><phrase
- role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
- role="identifier">no_state</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="promise_set_exception_bridgehead">
- <phrase id="promise_set_exception"/>
- <link linkend="promise_set_exception">Member
- function <code>set_exception</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">set_exception</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Store an exception pointer in the <link linkend="shared_state">shared
- state</link> and marks the state as ready.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">future_error</phrase></code> with
- <code><phrase role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
- role="identifier">future_already_satisfied</phrase></code> or <code><phrase
- role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
- role="identifier">no_state</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="swap_for_promise_bridgehead">
- <phrase id="swap_for_promise"/>
- <link linkend="swap_for_promise">Non-member function
- <code>swap()</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">promise</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">r</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Same as <code><phrase role="identifier">l</phrase><phrase role="special">.</phrase><phrase
- role="identifier">swap</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">r</phrase><phrase role="special">)</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section id="fiber.synchronization.futures.packaged_task">
- <title><anchor id="class_packaged_task"/><link linkend="fiber.synchronization.futures.packaged_task">Template
- <code><phrase role="identifier">packaged_task</phrase><phrase role="special"><></phrase></code></link></title>
- <para>
- A <link linkend="class_packaged_task"><code>packaged_task<></code></link> wraps a callable target that
- returns a value so that the return value can be computed asynchronously.
- </para>
- <para>
- Conventional usage of <code><phrase role="identifier">packaged_task</phrase><phrase
- role="special"><></phrase></code> is like this:
- </para>
- <orderedlist>
- <listitem>
- <simpara>
- Instantiate <code><phrase role="identifier">packaged_task</phrase><phrase
- role="special"><></phrase></code> with template arguments matching
- the signature of the callable. Pass the callable to the <link linkend="packaged_task_packaged_task">constructor</link>.
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- Call <link linkend="packaged_task_get_future"><code>packaged_task::get_future()</code></link> and capture
- the returned <link linkend="class_future"><code>future<></code></link> instance.
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- Launch a <link linkend="class_fiber"><code>fiber</code></link> to run the new <code><phrase role="identifier">packaged_task</phrase><phrase
- role="special"><></phrase></code>, passing any arguments required
- by the original callable.
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- Call <link linkend="fiber_detach"><code>fiber::detach()</code></link> on the newly-launched <code><phrase
- role="identifier">fiber</phrase></code>.
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- At some later point, retrieve the result from the <code><phrase role="identifier">future</phrase><phrase
- role="special"><></phrase></code>.
- </simpara>
- </listitem>
- </orderedlist>
- <para>
- This is, in fact, pretty much what <link linkend="fibers_async"><code>fibers::async()</code></link>
- encapsulates.
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">future</phrase><phrase role="special">/</phrase><phrase role="identifier">packaged_task</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">R</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">packaged_task</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase><phrase role="special">(</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase> <phrase role="special">></phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">packaged_task</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">explicit</phrase> <phrase role="identifier">packaged_task</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <ulink url="http://en.cppreference.com/w/cpp/concept/Allocator"><code><phrase role="identifier">Allocator</phrase></code></ulink> <phrase role="special">></phrase>
- <phrase role="identifier">packaged_task</phrase><phrase role="special">(</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <phrase role="identifier">Allocator</phrase> <phrase role="keyword">const</phrase><phrase role="special">&,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&);</phrase>
- <phrase role="identifier">packaged_task</phrase><phrase role="special">(</phrase> <phrase role="identifier">packaged_task</phrase> <phrase role="special">&&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">packaged_task</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">packaged_task</phrase> <phrase role="special">&&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">packaged_task</phrase><phrase role="special">(</phrase> <phrase role="identifier">packaged_task</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">packaged_task</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">packaged_task</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="special">~</phrase><phrase role="identifier">packaged_task</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">packaged_task</phrase> <phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">valid</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="identifier">get_future</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">void</phrase> <phrase role="keyword">operator</phrase><phrase role="special">()(</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">...);</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">reset</phrase><phrase role="special">();</phrase>
- <phrase role="special">};</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Signature</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">packaged_task</phrase><phrase role="special"><</phrase> <phrase role="identifier">Signature</phrase> <phrase role="special">></phrase> <phrase role="special">&,</phrase> <phrase role="identifier">packaged_task</phrase><phrase role="special"><</phrase> <phrase role="identifier">Signature</phrase> <phrase role="special">></phrase> <phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <bridgehead renderas="sect5" id="fiber.synchronization.futures.packaged_task.h0">
- <phrase id="fiber.synchronization.futures.packaged_task.default_constructor__code__phrase_role__identifier__packaged_task__phrase__phrase_role__special______phrase___code_"/><link
- linkend="fiber.synchronization.futures.packaged_task.default_constructor__code__phrase_role__identifier__packaged_task__phrase__phrase_role__special______phrase___code_">Default
- constructor <code><phrase role="identifier">packaged_task</phrase><phrase
- role="special">()</phrase></code></link>
- </bridgehead>
- <programlisting><phrase role="identifier">packaged_task</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Constructs an object of class <code><phrase role="identifier">packaged_task</phrase></code>
- with no <link linkend="shared_state">shared state</link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <anchor id="packaged_task_packaged_task"/>
- <bridgehead renderas="sect5" id="fiber.synchronization.futures.packaged_task.h1">
- <phrase id="fiber.synchronization.futures.packaged_task.templated_constructor__code__phrase_role__identifier__packaged_task__phrase__phrase_role__special______phrase___code_"/><link
- linkend="fiber.synchronization.futures.packaged_task.templated_constructor__code__phrase_role__identifier__packaged_task__phrase__phrase_role__special______phrase___code_">Templated
- constructor <code><phrase role="identifier">packaged_task</phrase><phrase
- role="special">()</phrase></code></link>
- </bridgehead>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">explicit</phrase> <phrase role="identifier">packaged_task</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">fn</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <ulink url="http://en.cppreference.com/w/cpp/concept/Allocator"><code><phrase role="identifier">Allocator</phrase></code></ulink> <phrase role="special">></phrase>
- <phrase role="identifier">packaged_task</phrase><phrase role="special">(</phrase> <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">allocator_arg_t</phrase></code></ulink><phrase role="special">,</phrase> <phrase role="identifier">Allocator</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">alloc</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">fn</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Constructs an object of class <code><phrase role="identifier">packaged_task</phrase></code>
- with a <link linkend="shared_state">shared state</link> and copies
- or moves the callable target <code><phrase role="identifier">fn</phrase></code>
- to internal storage.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Exceptions caused by memory allocation.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- The signature of <code><phrase role="identifier">Fn</phrase></code>
- should have a return type convertible to <code><phrase role="identifier">R</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>See also:</term>
- <listitem>
- <para>
- <ulink url="http://en.cppreference.com/w/cpp/memory/allocator_arg_t"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">allocator_arg_t</phrase></code></ulink>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect5" id="fiber.synchronization.futures.packaged_task.h2">
- <phrase id="fiber.synchronization.futures.packaged_task.move_constructor"/><link
- linkend="fiber.synchronization.futures.packaged_task.move_constructor">Move
- constructor</link>
- </bridgehead>
- <programlisting><phrase role="identifier">packaged_task</phrase><phrase role="special">(</phrase> <phrase role="identifier">packaged_task</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Creates a packaged_task by moving the <link linkend="shared_state">shared
- state</link> from <code><phrase role="identifier">other</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postcondition:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">other</phrase></code> contains no
- valid shared state.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect5" id="fiber.synchronization.futures.packaged_task.h3">
- <phrase id="fiber.synchronization.futures.packaged_task.destructor"/><link
- linkend="fiber.synchronization.futures.packaged_task.destructor">Destructor</link>
- </bridgehead>
- <programlisting><phrase role="special">~</phrase><phrase role="identifier">packaged_task</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Destroys <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>
- and abandons the <link linkend="shared_state">shared state</link>
- if shared state is ready; otherwise stores <code><phrase role="identifier">future_error</phrase></code>
- with error condition <code><phrase role="identifier">future_errc</phrase><phrase
- role="special">::</phrase><phrase role="identifier">broken_promise</phrase></code>
- as if by <link linkend="promise_set_exception"><code>promise::set_exception()</code></link>: the shared
- state is set ready.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="packaged_task_operator_assign_bridgehead">
- <phrase id="packaged_task_operator_assign"/>
- <link linkend="packaged_task_operator_assign">Member
- function <code>operator=</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">packaged_task</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">packaged_task</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Transfers the ownership of <link linkend="shared_state">shared state</link>
- to <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postcondition:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">other</phrase></code> contains no
- valid shared state.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="packaged_task_swap_bridgehead">
- <phrase id="packaged_task_swap"/>
- <link linkend="packaged_task_swap">Member
- function <code>swap</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">packaged_task</phrase> <phrase role="special">&</phrase> <phrase role="identifier">other</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Swaps the <link linkend="shared_state">shared state</link> between
- other and <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="packaged_task_valid_bridgehead">
- <phrase id="packaged_task_valid"/>
- <link linkend="packaged_task_valid">Member
- function <code>valid</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="identifier">valid</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Returns <code><phrase role="keyword">true</phrase></code> if <code><phrase
- role="special">*</phrase><phrase role="keyword">this</phrase></code>
- contains a <link linkend="shared_state">shared state</link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="packaged_task_get_future_bridgehead">
- <phrase id="packaged_task_get_future"/>
- <link linkend="packaged_task_get_future">Member
- function <code>get_future</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">R</phrase> <phrase role="special">></phrase> <phrase role="identifier">get_future</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- A <link linkend="class_future"><code>future<></code></link> with the same <link linkend="shared_state">shared
- state</link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">future_error</phrase></code> with
- <code><phrase role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
- role="identifier">future_already_retrieved</phrase></code> or <code><phrase
- role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
- role="identifier">no_state</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="packaged_task_operator_apply_bridgehead">
- <phrase id="packaged_task_operator_apply"/>
- <link linkend="packaged_task_operator_apply">Member
- function <code>operator()</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="keyword">operator</phrase><phrase role="special">()(</phrase> <phrase role="identifier">Args</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">args</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Invokes the stored callable target. Any exception thrown by the callable
- target <code><phrase role="identifier">fn</phrase></code> is stored
- in the <link linkend="shared_state">shared state</link> as if by
- <link linkend="promise_set_exception"><code>promise::set_exception()</code></link>. Otherwise, the value
- returned by <code><phrase role="identifier">fn</phrase></code> is
- stored in the shared state as if by <link linkend="promise_set_value"><code>promise::set_value()</code></link>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">future_error</phrase></code> with
- <code><phrase role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
- role="identifier">no_state</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="packaged_task_reset_bridgehead">
- <phrase id="packaged_task_reset"/>
- <link linkend="packaged_task_reset">Member
- function <code>reset</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">reset</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Resets the <link linkend="shared_state">shared state</link> and abandons
- the result of previous executions. A new shared state is constructed.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">future_error</phrase></code> with
- <code><phrase role="identifier">future_errc</phrase><phrase role="special">::</phrase><phrase
- role="identifier">no_state</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="swap_for_packaged_task_bridgehead">
- <phrase id="swap_for_packaged_task"/>
- <link linkend="swap_for_packaged_task">Non-member
- function <code>swap()</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Signature</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">swap</phrase><phrase role="special">(</phrase> <phrase role="identifier">packaged_task</phrase><phrase role="special"><</phrase> <phrase role="identifier">Signature</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">l</phrase><phrase role="special">,</phrase> <phrase role="identifier">packaged_task</phrase><phrase role="special"><</phrase> <phrase role="identifier">Signature</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">r</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Same as <code><phrase role="identifier">l</phrase><phrase role="special">.</phrase><phrase
- role="identifier">swap</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">r</phrase><phrase role="special">)</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- </section>
- </section>
- <section id="fiber.fls">
- <title><link linkend="fiber.fls">Fiber local storage</link></title>
- <bridgehead renderas="sect3" id="fiber.fls.h0">
- <phrase id="fiber.fls.synopsis"/><link linkend="fiber.fls.synopsis">Synopsis</link>
- </bridgehead>
- <para>
- Fiber local storage allows a separate instance of a given data item for each
- fiber.
- </para>
- <bridgehead renderas="sect3" id="fiber.fls.h1">
- <phrase id="fiber.fls.cleanup_at_fiber_exit"/><link linkend="fiber.fls.cleanup_at_fiber_exit">Cleanup
- at fiber exit</link>
- </bridgehead>
- <para>
- When a fiber exits, the objects associated with each <link linkend="class_fiber_specific_ptr"><code>fiber_specific_ptr</code></link> instance
- are destroyed. By default, the object pointed to by a pointer <code><phrase
- role="identifier">p</phrase></code> is destroyed by invoking <code><phrase
- role="keyword">delete</phrase> <phrase role="identifier">p</phrase></code>,
- but this can be overridden for a specific instance of <link linkend="class_fiber_specific_ptr"><code>fiber_specific_ptr</code></link> by
- providing a cleanup routine <code><phrase role="identifier">func</phrase></code>
- to the constructor. In this case, the object is destroyed by invoking <code><phrase
- role="identifier">func</phrase><phrase role="special">(</phrase><phrase role="identifier">p</phrase><phrase
- role="special">)</phrase></code>. The cleanup functions are called in an unspecified
- order.
- </para>
- <para>
- <bridgehead renderas="sect4" id="class_fiber_specific_ptr_bridgehead">
- <phrase id="class_fiber_specific_ptr"/>
- <link linkend="class_fiber_specific_ptr">Class
- <code>fiber_specific_ptr</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">fss</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">fiber_specific_ptr</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">T</phrase> <phrase role="identifier">element_type</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">fiber_specific_ptr</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">explicit</phrase> <phrase role="identifier">fiber_specific_ptr</phrase><phrase role="special">(</phrase> <phrase role="keyword">void</phrase><phrase role="special">(*</phrase><phrase role="identifier">fn</phrase><phrase role="special">)(</phrase><phrase role="identifier">T</phrase><phrase role="special">*)</phrase> <phrase role="special">);</phrase>
- <phrase role="special">~</phrase><phrase role="identifier">fiber_specific_ptr</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">fiber_specific_ptr</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber_specific_ptr</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">fiber_specific_ptr</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">fiber_specific_ptr</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">T</phrase> <phrase role="special">*</phrase> <phrase role="identifier">get</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">T</phrase> <phrase role="special">*</phrase> <phrase role="keyword">operator</phrase><phrase role="special">->()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">T</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">*()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">T</phrase> <phrase role="special">*</phrase> <phrase role="identifier">release</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">reset</phrase><phrase role="special">(</phrase> <phrase role="identifier">T</phrase> <phrase role="special">*);</phrase>
- <phrase role="special">};</phrase>
- <phrase role="special">}}</phrase>
- </programlisting>
- <bridgehead renderas="sect3" id="fiber.fls.h2">
- <phrase id="fiber.fls.constructor"/><link linkend="fiber.fls.constructor">Constructor</link>
- </bridgehead>
- <programlisting><phrase role="identifier">fiber_specific_ptr</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">explicit</phrase> <phrase role="identifier">fiber_specific_ptr</phrase><phrase role="special">(</phrase> <phrase role="keyword">void</phrase><phrase role="special">(*</phrase><phrase role="identifier">fn</phrase><phrase role="special">)(</phrase><phrase role="identifier">T</phrase><phrase role="special">*)</phrase> <phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Requires:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">delete</phrase> <phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">get</phrase><phrase
- role="special">()</phrase></code> is well-formed; <code><phrase role="identifier">fn</phrase><phrase
- role="special">(</phrase><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">get</phrase><phrase
- role="special">())</phrase></code> does not throw
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Construct a <link linkend="class_fiber_specific_ptr"><code>fiber_specific_ptr</code></link> object for storing
- a pointer to an object of type <code><phrase role="identifier">T</phrase></code>
- specific to each fiber. When <code><phrase role="identifier">reset</phrase><phrase
- role="special">()</phrase></code> is called, or the fiber exits, <link linkend="class_fiber_specific_ptr"><code>fiber_specific_ptr</code></link> calls
- <code><phrase role="identifier">fn</phrase><phrase role="special">(</phrase><phrase
- role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">get</phrase><phrase role="special">())</phrase></code>.
- If the no-arguments constructor is used, the default <code><phrase role="keyword">delete</phrase></code>-based
- cleanup function will be used to destroy the fiber-local objects.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">fiber_error</phrase></code> if an error
- occurs.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <bridgehead renderas="sect3" id="fiber.fls.h3">
- <phrase id="fiber.fls.destructor"/><link linkend="fiber.fls.destructor">Destructor</link>
- </bridgehead>
- <programlisting><phrase role="special">~</phrase><phrase role="identifier">fiber_specific_ptr</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Requires:</term>
- <listitem>
- <para>
- All the fiber specific instances associated to this <link linkend="class_fiber_specific_ptr"><code>fiber_specific_ptr</code></link>
- (except
- maybe the one associated to this fiber) must be nullptr.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Calls <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">reset</phrase><phrase role="special">()</phrase></code>
- to clean up the associated value for the current fiber, and destroys
- <code><phrase role="special">*</phrase><phrase role="keyword">this</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Remarks:</term>
- <listitem>
- <para>
- The requirement is an implementation restriction. If the destructor promised
- to delete instances for all fibers, the implementation would be forced
- to maintain a list of all the fibers having an associated specific ptr,
- which is against the goal of fiber specific data. In general, a <link linkend="class_fiber_specific_ptr"><code>fiber_specific_ptr</code></link> should
- outlive the fibers that use it.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <note>
- <para>
- Care needs to be taken to ensure that any fibers still running after an instance
- of <link linkend="class_fiber_specific_ptr"><code>fiber_specific_ptr</code></link> has been destroyed do not call
- any member functions on that instance.
- </para>
- </note>
- <para>
- <bridgehead renderas="sect4" id="fiber_specific_ptr_get_bridgehead">
- <phrase id="fiber_specific_ptr_get"/>
- <link linkend="fiber_specific_ptr_get">Member
- function <code>get</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">T</phrase> <phrase role="special">*</phrase> <phrase role="identifier">get</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- The pointer associated with the current fiber.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <note>
- <para>
- The initial value associated with an instance of <link linkend="class_fiber_specific_ptr"><code>fiber_specific_ptr</code></link> is
- <code><phrase role="keyword">nullptr</phrase></code> for each fiber.
- </para>
- </note>
- <para>
- <bridgehead renderas="sect4" id="fiber_specific_ptr_operator_arrow_bridgehead">
- <phrase id="fiber_specific_ptr_operator_arrow"/>
- <link linkend="fiber_specific_ptr_operator_arrow">Member
- function <code>operator-></code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">T</phrase> <phrase role="special">*</phrase> <phrase role="keyword">operator</phrase><phrase role="special">->()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Requires:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">get</phrase><phrase role="special">()</phrase></code>
- is not <code><phrase role="keyword">nullptr</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">get</phrase><phrase role="special">()</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="fiber_specific_ptr_operator_star_bridgehead">
- <phrase id="fiber_specific_ptr_operator_star"/>
- <link linkend="fiber_specific_ptr_operator_star">Member
- function <code>operator*</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">T</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">*()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Requires:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">get</phrase><phrase role="special">()</phrase></code>
- is not <code><phrase role="keyword">nullptr</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="special">*(</phrase><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">get</phrase><phrase
- role="special">())</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="fiber_specific_ptr_release_bridgehead">
- <phrase id="fiber_specific_ptr_release"/>
- <link linkend="fiber_specific_ptr_release">Member
- function <code>release</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">T</phrase> <phrase role="special">*</phrase> <phrase role="identifier">release</phrase><phrase role="special">();</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Return <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">get</phrase><phrase role="special">()</phrase></code>
- and store <code><phrase role="keyword">nullptr</phrase></code> as the
- pointer associated with the current fiber without invoking the cleanup
- function.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postcondition:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">get</phrase><phrase role="special">()==</phrase><phrase
- role="keyword">nullptr</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="fiber_specific_ptr_reset_bridgehead">
- <phrase id="fiber_specific_ptr_reset"/>
- <link linkend="fiber_specific_ptr_reset">Member
- function <code>reset</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">reset</phrase><phrase role="special">(</phrase> <phrase role="identifier">T</phrase> <phrase role="special">*</phrase> <phrase role="identifier">new_value</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- If <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">get</phrase><phrase role="special">()!=</phrase><phrase
- role="identifier">new_value</phrase></code> and <code><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">get</phrase><phrase
- role="special">()</phrase></code> is not <code><phrase role="keyword">nullptr</phrase></code>,
- invoke <code><phrase role="keyword">delete</phrase> <phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">get</phrase><phrase
- role="special">()</phrase></code> or <code><phrase role="identifier">fn</phrase><phrase
- role="special">(</phrase><phrase role="keyword">this</phrase><phrase
- role="special">-></phrase><phrase role="identifier">get</phrase><phrase
- role="special">())</phrase></code> as appropriate. Store <code><phrase
- role="identifier">new_value</phrase></code> as the pointer associated
- with the current fiber.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Postcondition:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase
- role="identifier">get</phrase><phrase role="special">()==</phrase><phrase
- role="identifier">new_value</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Exception raised during cleanup of previous value.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section id="fiber.migration">
- <title><anchor id="migration"/><link linkend="fiber.migration">Migrating fibers
- between threads</link></title>
- <bridgehead renderas="sect3" id="fiber.migration.h0">
- <phrase id="fiber.migration.overview"/><link linkend="fiber.migration.overview">Overview</link>
- </bridgehead>
- <para>
- Each fiber owns a stack and manages its execution state, including all registers
- and CPU flags, the instruction pointer and the stack pointer. That means, in
- general, a fiber is not bound to a specific thread.<footnote id="fiber.migration.f0">
- <para>
- The <quote>main</quote> fiber on each thread, that is, the fiber on which
- the thread is launched, cannot migrate to any other thread. Also <emphasis
- role="bold">Boost.Fiber</emphasis> implicitly creates a dispatcher fiber
- for each thread — this cannot migrate either.
- </para>
- </footnote><superscript>,</superscript><footnote id="fiber.migration.f1">
- <para>
- Of course it would be problematic to migrate a fiber that relies on <link
- linkend="thread_local_storage">thread-local storage</link>.
- </para>
- </footnote>
- </para>
- <para>
- Migrating a fiber from a logical CPU with heavy workload to another logical
- CPU with a lighter workload might speed up the overall execution. Note that
- in the case of NUMA-architectures, it is not always advisable to migrate data
- between threads. Suppose fiber <emphasis>f</emphasis> is running on logical
- CPU <emphasis>cpu0</emphasis> which belongs to NUMA node <emphasis>node0</emphasis>.
- The data of <emphasis>f</emphasis> are allocated on the physical memory located
- at <emphasis>node0</emphasis>. Migrating the fiber from <emphasis>cpu0</emphasis>
- to another logical CPU <emphasis>cpuX</emphasis> which is part of a different
- NUMA node <emphasis>nodeX</emphasis> might reduce the performance of the application
- due to increased latency of memory access.
- </para>
- <para>
- Only fibers that are contained in <link linkend="class_algorithm"><code>algorithm</code></link>’s ready queue can
- migrate between threads. You cannot migrate a running fiber, nor one that is
- <link linkend="blocking"><emphasis>blocked</emphasis></link>. You cannot migrate
- a fiber if its <link linkend="context_is_context"><code>context::is_context()</code></link> method returns <code><phrase
- role="keyword">true</phrase></code> for <code><phrase role="identifier">pinned_context</phrase></code>.
- </para>
- <para>
- In <emphasis role="bold">Boost.Fiber</emphasis> a fiber is migrated by invoking
- <link linkend="context_detach"><code>context::detach()</code></link> on the thread from which the fiber migrates
- and <link linkend="context_attach"><code>context::attach()</code></link> on the thread to which the fiber migrates.
- </para>
- <para>
- Thus, fiber migration is accomplished by sharing state between instances of
- a user-coded <link linkend="class_algorithm"><code>algorithm</code></link> implementation running on different threads.
- The fiber’s original thread calls <link linkend="algorithm_awakened"><code>algorithm::awakened()</code></link>, passing
- the fiber’s <link linkend="class_context"><code>context</code></link><literal>*</literal>. The <code><phrase role="identifier">awakened</phrase><phrase
- role="special">()</phrase></code> implementation calls <link linkend="context_detach"><code>context::detach()</code></link>.
- </para>
- <para>
- At some later point, when the same or a different thread calls <link linkend="algorithm_pick_next"><code>algorithm::pick_next()</code></link>,
- the <code><phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase></code>
- implementation selects a ready fiber and calls <link linkend="context_attach"><code>context::attach()</code></link> on
- it before returning it.
- </para>
- <para>
- As stated above, a <code><phrase role="identifier">context</phrase></code>
- for which <code><phrase role="identifier">is_context</phrase><phrase role="special">(</phrase><phrase
- role="identifier">pinned_context</phrase><phrase role="special">)</phrase>
- <phrase role="special">==</phrase> <phrase role="keyword">true</phrase></code>
- must never be passed to either <link linkend="context_detach"><code>context::detach()</code></link> or <link linkend="context_attach"><code>context::attach()</code></link>.
- It may only be returned from <code><phrase role="identifier">pick_next</phrase><phrase
- role="special">()</phrase></code> called by the <emphasis>same</emphasis> thread
- that passed that context to <code><phrase role="identifier">awakened</phrase><phrase
- role="special">()</phrase></code>.
- </para>
- <bridgehead renderas="sect3" id="fiber.migration.h1">
- <phrase id="fiber.migration.example_of_work_sharing"/><link linkend="fiber.migration.example_of_work_sharing">Example
- of work sharing</link>
- </bridgehead>
- <para>
- In the example <ulink url="../../examples/work_sharing.cpp">work_sharing.cpp</ulink>
- multiple worker fibers are created on the main thread. Each fiber gets a character
- as parameter at construction. This character is printed out ten times. Between
- each iteration the fiber calls <link linkend="this_fiber_yield"><code>this_fiber::yield()</code></link>. That puts
- the fiber in the ready queue of the fiber-scheduler <emphasis>shared_ready_queue</emphasis>,
- running in the current thread. The next fiber ready to be executed is dequeued
- from the shared ready queue and resumed by <emphasis>shared_ready_queue</emphasis>
- running on <emphasis>any participating thread</emphasis>.
- </para>
- <para>
- All instances of <emphasis>shared_ready_queue</emphasis> share one global concurrent
- queue, used as ready queue. This mechanism shares all worker fibers between
- all instances of <emphasis>shared_ready_queue</emphasis>, thus between all
- participating threads.
- </para>
- <bridgehead renderas="sect3" id="fiber.migration.h2">
- <phrase id="fiber.migration.setup_of_threads_and_fibers"/><link linkend="fiber.migration.setup_of_threads_and_fibers">Setup
- of threads and fibers</link>
- </bridgehead>
- <para>
- In <code><phrase role="identifier">main</phrase><phrase role="special">()</phrase></code>
- the fiber-scheduler is installed and the worker fibers and the threads are
- launched.
- </para>
- <para>
- <programlisting><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">algo</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_work</phrase> <phrase role="special">>();</phrase> <co id="fiber.migration.c0" linkends="fiber.migration.c1" />
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">char</phrase> <phrase role="identifier">c</phrase> <phrase role="special">:</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase><phrase role="special">(</phrase><phrase role="string">"abcdefghijklmnopqrstuvwxyz"</phrase><phrase role="special">))</phrase> <phrase role="special">{</phrase> <co id="fiber.migration.c2" linkends="fiber.migration.c3" />
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">([</phrase><phrase role="identifier">c</phrase><phrase role="special">](){</phrase> <phrase role="identifier">whatevah</phrase><phrase role="special">(</phrase> <phrase role="identifier">c</phrase><phrase role="special">);</phrase> <phrase role="special">}).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
- <phrase role="special">++</phrase><phrase role="identifier">fiber_count</phrase><phrase role="special">;</phrase> <co id="fiber.migration.c4" linkends="fiber.migration.c5" />
- <phrase role="special">}</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">thread_barrier</phrase> <phrase role="identifier">b</phrase><phrase role="special">(</phrase> <phrase role="number">4</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase> <phrase role="identifier">threads</phrase><phrase role="special">[]</phrase> <phrase role="special">=</phrase> <phrase role="special">{</phrase> <co id="fiber.migration.c6" linkends="fiber.migration.c7" />
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">thread</phrase><phrase role="special">,</phrase> <phrase role="special">&</phrase> <phrase role="identifier">b</phrase><phrase role="special">),</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">thread</phrase><phrase role="special">,</phrase> <phrase role="special">&</phrase> <phrase role="identifier">b</phrase><phrase role="special">),</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">thread</phrase><phrase role="special">,</phrase> <phrase role="special">&</phrase> <phrase role="identifier">b</phrase><phrase role="special">)</phrase>
- <phrase role="special">};</phrase>
- <phrase role="identifier">b</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">();</phrase> <co id="fiber.migration.c8" linkends="fiber.migration.c9" />
- <phrase role="special">{</phrase>
- <phrase role="identifier">lock_type</phrase><co id="fiber.migration.c10" linkends="fiber.migration.c11" /> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx_count</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">cnd_count</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="number">0</phrase> <phrase role="special">==</phrase> <phrase role="identifier">fiber_count</phrase><phrase role="special">;</phrase> <phrase role="special">}</phrase> <phrase role="special">);</phrase> <co id="fiber.migration.c12" linkends="fiber.migration.c13" />
- <phrase role="special">}</phrase> <co id="fiber.migration.c14" linkends="fiber.migration.c15" />
- <phrase role="identifier">BOOST_ASSERT</phrase><phrase role="special">(</phrase> <phrase role="number">0</phrase> <phrase role="special">==</phrase> <phrase role="identifier">fiber_count</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase> <phrase role="special">&</phrase> <phrase role="identifier">t</phrase> <phrase role="special">:</phrase> <phrase role="identifier">threads</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase> <co id="fiber.migration.c16" linkends="fiber.migration.c17" />
- <phrase role="identifier">t</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <calloutlist>
- <callout arearefs="fiber.migration.c0" id="fiber.migration.c1">
- <para>
- Install the scheduling algorithm <code><phrase role="identifier">boost</phrase><phrase
- role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase
- role="special">::</phrase><phrase role="identifier">algo</phrase><phrase
- role="special">::</phrase><phrase role="identifier">shared_work</phrase></code>
- in the main thread too, so each new fiber gets launched into the shared
- pool.
- </para>
- </callout>
- <callout arearefs="fiber.migration.c2" id="fiber.migration.c3">
- <para>
- Launch a number of worker fibers; each worker fiber picks up a character
- that is passed as parameter to fiber-function <code><phrase role="identifier">whatevah</phrase></code>.
- Each worker fiber gets detached.
- </para>
- </callout>
- <callout arearefs="fiber.migration.c4" id="fiber.migration.c5">
- <para>
- Increment fiber counter for each new fiber.
- </para>
- </callout>
- <callout arearefs="fiber.migration.c6" id="fiber.migration.c7">
- <para>
- Launch a couple of threads that join the work sharing.
- </para>
- </callout>
- <callout arearefs="fiber.migration.c8" id="fiber.migration.c9">
- <para>
- sync with other threads: allow them to start processing
- </para>
- </callout>
- <callout arearefs="fiber.migration.c10" id="fiber.migration.c11">
- <para>
- <code><phrase role="identifier">lock_type</phrase></code> is typedef'ed
- as <ulink url="http://en.cppreference.com/w/cpp/thread/unique_lock"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">unique_lock</phrase></code></ulink>< <ulink url="http://en.cppreference.com/w/cpp/thread/mutex"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">mutex</phrase></code></ulink> >
- </para>
- </callout>
- <callout arearefs="fiber.migration.c12" id="fiber.migration.c13">
- <para>
- Suspend main fiber and resume worker fibers in the meanwhile. Main fiber
- gets resumed (e.g returns from <code><phrase role="identifier">condition_variable_any</phrase><phrase
- role="special">::</phrase><phrase role="identifier">wait</phrase><phrase
- role="special">()</phrase></code>) if all worker fibers are complete.
- </para>
- </callout>
- <callout arearefs="fiber.migration.c14" id="fiber.migration.c15">
- <para>
- Releasing lock of mtx_count is required before joining the threads, otherwise
- the other threads would be blocked inside condition_variable::wait() and
- would never return (deadlock).
- </para>
- </callout>
- <callout arearefs="fiber.migration.c16" id="fiber.migration.c17">
- <para>
- wait for threads to terminate
- </para>
- </callout>
- </calloutlist>
- <para>
- The start of the threads is synchronized with a barrier. The main fiber of
- each thread (including main thread) is suspended until all worker fibers are
- complete. When the main fiber returns from <link linkend="condition_variable_wait"><code>condition_variable::wait()</code></link>,
- the thread terminates: the main thread joins all other threads.
- </para>
- <para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">thread_barrier</phrase> <phrase role="special">*</phrase> <phrase role="identifier">b</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ostringstream</phrase> <phrase role="identifier">buffer</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">buffer</phrase> <phrase role="special"><<</phrase> <phrase role="string">"thread started "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">this_thread</phrase><phrase role="special">::</phrase><phrase role="identifier">get_id</phrase><phrase role="special">()</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">buffer</phrase><phrase role="special">.</phrase><phrase role="identifier">str</phrase><phrase role="special">()</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">flush</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">algo</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_work</phrase> <phrase role="special">>();</phrase> <co id="fiber.migration.c18" linkends="fiber.migration.c19" />
- <phrase role="identifier">b</phrase><phrase role="special">-></phrase><phrase role="identifier">wait</phrase><phrase role="special">();</phrase> <co id="fiber.migration.c20" linkends="fiber.migration.c21" />
- <phrase role="identifier">lock_type</phrase> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx_count</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">cnd_count</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="number">0</phrase> <phrase role="special">==</phrase> <phrase role="identifier">fiber_count</phrase><phrase role="special">;</phrase> <phrase role="special">}</phrase> <phrase role="special">);</phrase> <co id="fiber.migration.c22" linkends="fiber.migration.c23" />
- <phrase role="identifier">BOOST_ASSERT</phrase><phrase role="special">(</phrase> <phrase role="number">0</phrase> <phrase role="special">==</phrase> <phrase role="identifier">fiber_count</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <calloutlist>
- <callout arearefs="fiber.migration.c18" id="fiber.migration.c19">
- <para>
- Install the scheduling algorithm <code><phrase role="identifier">boost</phrase><phrase
- role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase
- role="special">::</phrase><phrase role="identifier">algo</phrase><phrase
- role="special">::</phrase><phrase role="identifier">shared_work</phrase></code>
- in order to join the work sharing.
- </para>
- </callout>
- <callout arearefs="fiber.migration.c20" id="fiber.migration.c21">
- <para>
- sync with other threads: allow them to start processing
- </para>
- </callout>
- <callout arearefs="fiber.migration.c22" id="fiber.migration.c23">
- <para>
- Suspend main fiber and resume worker fibers in the meanwhile. Main fiber
- gets resumed (e.g returns from <code><phrase role="identifier">condition_variable_any</phrase><phrase
- role="special">::</phrase><phrase role="identifier">wait</phrase><phrase
- role="special">()</phrase></code>) if all worker fibers are complete.
- </para>
- </callout>
- </calloutlist>
- <para>
- Each worker fiber executes function <code><phrase role="identifier">whatevah</phrase><phrase
- role="special">()</phrase></code> with character <code><phrase role="identifier">me</phrase></code>
- as parameter. The fiber yields in a loop and prints out a message if it was
- migrated to another thread.
- </para>
- <para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">whatevah</phrase><phrase role="special">(</phrase> <phrase role="keyword">char</phrase> <phrase role="identifier">me</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">try</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">::</phrase><phrase role="identifier">id</phrase> <phrase role="identifier">my_thread</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">this_thread</phrase><phrase role="special">::</phrase><phrase role="identifier">get_id</phrase><phrase role="special">();</phrase> <co id="fiber.migration.c24" linkends="fiber.migration.c25" />
- <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ostringstream</phrase> <phrase role="identifier">buffer</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">buffer</phrase> <phrase role="special"><<</phrase> <phrase role="string">"fiber "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">me</phrase> <phrase role="special"><<</phrase> <phrase role="string">" started on thread "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">my_thread</phrase> <phrase role="special"><<</phrase> <phrase role="char">'\n'</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">buffer</phrase><phrase role="special">.</phrase><phrase role="identifier">str</phrase><phrase role="special">()</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">flush</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">unsigned</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special"><</phrase> <phrase role="number">10</phrase><phrase role="special">;</phrase> <phrase role="special">++</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase> <co id="fiber.migration.c26" linkends="fiber.migration.c27" />
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">yield</phrase><phrase role="special">();</phrase> <co id="fiber.migration.c28" linkends="fiber.migration.c29" />
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">::</phrase><phrase role="identifier">id</phrase> <phrase role="identifier">new_thread</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">this_thread</phrase><phrase role="special">::</phrase><phrase role="identifier">get_id</phrase><phrase role="special">();</phrase> <co id="fiber.migration.c30" linkends="fiber.migration.c31" />
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">new_thread</phrase> <phrase role="special">!=</phrase> <phrase role="identifier">my_thread</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase> <co id="fiber.migration.c32" linkends="fiber.migration.c33" />
- <phrase role="identifier">my_thread</phrase> <phrase role="special">=</phrase> <phrase role="identifier">new_thread</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ostringstream</phrase> <phrase role="identifier">buffer</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">buffer</phrase> <phrase role="special"><<</phrase> <phrase role="string">"fiber "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">me</phrase> <phrase role="special"><<</phrase> <phrase role="string">" switched to thread "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">my_thread</phrase> <phrase role="special"><<</phrase> <phrase role="char">'\n'</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">buffer</phrase><phrase role="special">.</phrase><phrase role="identifier">str</phrase><phrase role="special">()</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">flush</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase> <phrase role="keyword">catch</phrase> <phrase role="special">(</phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">lock_type</phrase> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx_count</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="number">0</phrase> <phrase role="special">==</phrase> <phrase role="special">--</phrase><phrase role="identifier">fiber_count</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase> <co id="fiber.migration.c34" linkends="fiber.migration.c35" />
- <phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">cnd_count</phrase><phrase role="special">.</phrase><phrase role="identifier">notify_all</phrase><phrase role="special">();</phrase> <co id="fiber.migration.c36" linkends="fiber.migration.c37" />
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <calloutlist>
- <callout arearefs="fiber.migration.c24" id="fiber.migration.c25">
- <para>
- get ID of initial thread
- </para>
- </callout>
- <callout arearefs="fiber.migration.c26" id="fiber.migration.c27">
- <para>
- loop ten times
- </para>
- </callout>
- <callout arearefs="fiber.migration.c28" id="fiber.migration.c29">
- <para>
- yield to other fibers
- </para>
- </callout>
- <callout arearefs="fiber.migration.c30" id="fiber.migration.c31">
- <para>
- get ID of current thread
- </para>
- </callout>
- <callout arearefs="fiber.migration.c32" id="fiber.migration.c33">
- <para>
- test if fiber was migrated to another thread
- </para>
- </callout>
- <callout arearefs="fiber.migration.c34" id="fiber.migration.c35">
- <para>
- Decrement fiber counter for each completed fiber.
- </para>
- </callout>
- <callout arearefs="fiber.migration.c36" id="fiber.migration.c37">
- <para>
- Notify all fibers waiting on <code><phrase role="identifier">cnd_count</phrase></code>.
- </para>
- </callout>
- </calloutlist>
- <bridgehead renderas="sect3" id="fiber.migration.h3">
- <phrase id="fiber.migration.scheduling_fibers"/><link linkend="fiber.migration.scheduling_fibers">Scheduling
- fibers</link>
- </bridgehead>
- <para>
- The fiber scheduler <code><phrase role="identifier">shared_ready_queue</phrase></code>
- is like <code><phrase role="identifier">round_robin</phrase></code>, except
- that it shares a common ready queue among all participating threads. A thread
- participates in this pool by executing <link linkend="use_scheduling_algorithm"><code>use_scheduling_algorithm()</code></link>
- before
- any other <emphasis role="bold">Boost.Fiber</emphasis> operation.
- </para>
- <para>
- The important point about the ready queue is that it’s a class static, common
- to all instances of shared_ready_queue. Fibers that are enqueued via <link linkend="algorithm_awakened"><code>algorithm::awakened()</code></link> (fibers
- that are ready to be resumed) are thus available to all threads. It is required
- to reserve a separate, scheduler-specific queue for the thread’s main fiber
- and dispatcher fibers: these may <emphasis>not</emphasis> be shared between
- threads! When we’re passed either of these fibers, push it there instead of
- in the shared queue: it would be Bad News for thread B to retrieve and attempt
- to execute thread A’s main fiber.
- </para>
- <para>
- [awakened_ws]
- </para>
- <para>
- When <link linkend="algorithm_pick_next"><code>algorithm::pick_next()</code></link> gets called inside one thread,
- a fiber is dequeued from <emphasis>rqueue_</emphasis> and will be resumed in
- that thread.
- </para>
- <para>
- [pick_next_ws]
- </para>
- <para>
- The source code above is found in <ulink url="../../examples/work_sharing.cpp">work_sharing.cpp</ulink>.
- </para>
- </section>
- <section id="fiber.callbacks">
- <title><anchor id="callbacks"/><link linkend="fiber.callbacks">Integrating Fibers
- with Asynchronous Callbacks</link></title>
- <section id="fiber.callbacks.overview">
- <title><link linkend="fiber.callbacks.overview">Overview</link></title>
- <para>
- One of the primary benefits of <emphasis role="bold">Boost.Fiber</emphasis>
- is the ability to use asynchronous operations for efficiency, while at the
- same time structuring the calling code <emphasis>as if</emphasis> the operations
- were synchronous. Asynchronous operations provide completion notification
- in a variety of ways, but most involve a callback function of some kind.
- This section discusses tactics for interfacing <emphasis role="bold">Boost.Fiber</emphasis>
- with an arbitrary async operation.
- </para>
- <para>
- For purposes of illustration, consider the following hypothetical API:
- </para>
- <para>
- <programlisting><phrase role="keyword">class</phrase> <phrase role="identifier">AsyncAPI</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="comment">// constructor acquires some resource that can be read and written</phrase>
- <phrase role="identifier">AsyncAPI</phrase><phrase role="special">();</phrase>
- <phrase role="comment">// callbacks accept an int error code; 0 == success</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">errorcode</phrase><phrase role="special">;</phrase>
- <phrase role="comment">// write callback only needs to indicate success or failure</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">init_write</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">data</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">callback</phrase><phrase role="special">);</phrase>
- <phrase role="comment">// read callback needs to accept both errorcode and data</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">init_read</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">callback</phrase><phrase role="special">);</phrase>
- <phrase role="comment">// ... other operations ...</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <para>
- The significant points about each of <code><phrase role="identifier">init_write</phrase><phrase
- role="special">()</phrase></code> and <code><phrase role="identifier">init_read</phrase><phrase
- role="special">()</phrase></code> are:
- </para>
- <itemizedlist>
- <listitem>
- <simpara>
- The <code><phrase role="identifier">AsyncAPI</phrase></code> method only
- initiates the operation. It returns immediately, while the requested
- operation is still pending.
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- The method accepts a callback. When the operation completes, the callback
- is called with relevant parameters (error code, data if applicable).
- </simpara>
- </listitem>
- </itemizedlist>
- <para>
- We would like to wrap these asynchronous methods in functions that appear
- synchronous by blocking the calling fiber until the operation completes.
- This lets us use the wrapper function’s return value to deliver relevant data.
- </para>
- <tip>
- <para>
- <link linkend="class_promise"><code>promise<></code></link> and <link linkend="class_future"><code>future<></code></link> are your friends
- here.
- </para>
- </tip>
- </section>
- <section id="fiber.callbacks.return_errorcode">
- <title><link linkend="fiber.callbacks.return_errorcode">Return Errorcode</link></title>
- <para>
- The <code><phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase
- role="identifier">init_write</phrase><phrase role="special">()</phrase></code>
- callback passes only an <code><phrase role="identifier">errorcode</phrase></code>.
- If we simply want the blocking wrapper to return that <code><phrase role="identifier">errorcode</phrase></code>,
- this is an extremely straightforward use of <link linkend="class_promise"><code>promise<></code></link> and
- <link linkend="class_future"><code>future<></code></link>:
- </para>
- <para>
- <programlisting><phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">write_ec</phrase><phrase role="special">(</phrase> <phrase role="identifier">AsyncAPI</phrase> <phrase role="special">&</phrase> <phrase role="identifier">api</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">promise</phrase><phrase role="special"><</phrase> <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="special">></phrase> <phrase role="identifier">promise</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="special">></phrase> <phrase role="identifier">future</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">get_future</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// In general, even though we block waiting for future::get() and therefore</phrase>
- <phrase role="comment">// won't destroy 'promise' until promise::set_value() has been called, we</phrase>
- <phrase role="comment">// are advised that with threads it's possible for ~promise() to be</phrase>
- <phrase role="comment">// entered before promise::set_value() has returned. While that shouldn't</phrase>
- <phrase role="comment">// happen with fibers::promise, a robust way to deal with the lifespan</phrase>
- <phrase role="comment">// issue is to bind 'promise' into our lambda. Since promise is move-only,</phrase>
- <phrase role="comment">// use initialization capture.</phrase>
- <phrase role="preprocessor">#if</phrase> <phrase role="special">!</phrase> <phrase role="identifier">defined</phrase><phrase role="special">(</phrase><phrase role="identifier">BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES</phrase><phrase role="special">)</phrase>
- <phrase role="identifier">api</phrase><phrase role="special">.</phrase><phrase role="identifier">init_write</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">data</phrase><phrase role="special">,</phrase>
- <phrase role="special">[</phrase><phrase role="identifier">promise</phrase><phrase role="special">=</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special">)](</phrase> <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="keyword">mutable</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">ec</phrase><phrase role="special">);</phrase>
- <phrase role="special">});</phrase>
- <phrase role="preprocessor">#else</phrase> <phrase role="comment">// defined(BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES)</phrase>
- <phrase role="identifier">api</phrase><phrase role="special">.</phrase><phrase role="identifier">init_write</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">data</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">bind</phrase><phrase role="special">([](</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">promise</phrase><phrase role="special"><</phrase> <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">promise</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">ec</phrase><phrase role="special">);</phrase>
- <phrase role="special">},</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special">),</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">placeholders</phrase><phrase role="special">::</phrase><phrase role="identifier">_1</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="preprocessor">#endif</phrase> <phrase role="comment">// BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- All we have to do is:
- </para>
- <orderedlist>
- <listitem>
- <simpara>
- Instantiate a <code><phrase role="identifier">promise</phrase><phrase
- role="special"><></phrase></code> of correct type.
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- Obtain its <code><phrase role="identifier">future</phrase><phrase role="special"><></phrase></code>.
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- Arrange for the callback to call <link linkend="promise_set_value"><code>promise::set_value()</code></link>.
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- Block on <link linkend="future_get"><code>future::get()</code></link>.
- </simpara>
- </listitem>
- </orderedlist>
- <note>
- <para>
- This tactic for resuming a pending fiber works even if the callback is
- called on a different thread than the one on which the initiating fiber
- is running. In fact, <ulink url="../../examples/adapt_callbacks.cpp">the
- example program’s</ulink> dummy <code><phrase role="identifier">AsyncAPI</phrase></code>
- implementation illustrates that: it simulates async I/O by launching a
- new thread that sleeps briefly and then calls the relevant callback.
- </para>
- </note>
- </section>
- <section id="fiber.callbacks.success_or_exception">
- <title><link linkend="fiber.callbacks.success_or_exception">Success or Exception</link></title>
- <para>
- A wrapper more aligned with modern C++ practice would use an exception, rather
- than an <code><phrase role="identifier">errorcode</phrase></code>, to communicate
- failure to its caller. This is straightforward to code in terms of <code><phrase
- role="identifier">write_ec</phrase><phrase role="special">()</phrase></code>:
- </para>
- <para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">write</phrase><phrase role="special">(</phrase> <phrase role="identifier">AsyncAPI</phrase> <phrase role="special">&</phrase> <phrase role="identifier">api</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">ec</phrase> <phrase role="special">=</phrase> <phrase role="identifier">write_ec</phrase><phrase role="special">(</phrase> <phrase role="identifier">api</phrase><phrase role="special">,</phrase> <phrase role="identifier">data</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">throw</phrase> <phrase role="identifier">make_exception</phrase><phrase role="special">(</phrase><phrase role="string">"write"</phrase><phrase role="special">,</phrase> <phrase role="identifier">ec</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- The point is that since each fiber has its own stack, you need not repeat
- messy boilerplate: normal encapsulation works.
- </para>
- </section>
- <section id="fiber.callbacks.return_errorcode_or_data">
- <title><link linkend="fiber.callbacks.return_errorcode_or_data">Return Errorcode
- or Data</link></title>
- <para>
- Things get a bit more interesting when the async operation’s callback passes
- multiple data items of interest. One approach would be to use <code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">pair</phrase><phrase
- role="special"><></phrase></code> to capture both:
- </para>
- <para>
- <programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">pair</phrase><phrase role="special"><</phrase> <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></phrase> <phrase role="identifier">read_ec</phrase><phrase role="special">(</phrase> <phrase role="identifier">AsyncAPI</phrase> <phrase role="special">&</phrase> <phrase role="identifier">api</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">pair</phrase><phrase role="special"><</phrase> <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></phrase> <phrase role="identifier">result_pair</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">promise</phrase><phrase role="special"><</phrase> <phrase role="identifier">result_pair</phrase> <phrase role="special">></phrase> <phrase role="identifier">promise</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">result_pair</phrase> <phrase role="special">></phrase> <phrase role="identifier">future</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">get_future</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// We promise that both 'promise' and 'future' will survive until our</phrase>
- <phrase role="comment">// lambda has been called.</phrase>
- <phrase role="preprocessor">#if</phrase> <phrase role="special">!</phrase> <phrase role="identifier">defined</phrase><phrase role="special">(</phrase><phrase role="identifier">BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES</phrase><phrase role="special">)</phrase>
- <phrase role="identifier">api</phrase><phrase role="special">.</phrase><phrase role="identifier">init_read</phrase><phrase role="special">([</phrase><phrase role="identifier">promise</phrase><phrase role="special">=</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special">)](</phrase> <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">ec</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="keyword">mutable</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">result_pair</phrase><phrase role="special">(</phrase> <phrase role="identifier">ec</phrase><phrase role="special">,</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="special">});</phrase>
- <phrase role="preprocessor">#else</phrase> <phrase role="comment">// defined(BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES)</phrase>
- <phrase role="identifier">api</phrase><phrase role="special">.</phrase><phrase role="identifier">init_read</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">bind</phrase><phrase role="special">([](</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">promise</phrase><phrase role="special"><</phrase> <phrase role="identifier">result_pair</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">promise</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">ec</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="keyword">mutable</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">result_pair</phrase><phrase role="special">(</phrase> <phrase role="identifier">ec</phrase><phrase role="special">,</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="special">},</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special">),</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">placeholders</phrase><phrase role="special">::</phrase><phrase role="identifier">_1</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">placeholders</phrase><phrase role="special">::</phrase><phrase role="identifier">_2</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="preprocessor">#endif</phrase> <phrase role="comment">// BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- Once you bundle the interesting data in <code><phrase role="identifier">std</phrase><phrase
- role="special">::</phrase><phrase role="identifier">pair</phrase><phrase
- role="special"><></phrase></code>, the code is effectively identical
- to <code><phrase role="identifier">write_ec</phrase><phrase role="special">()</phrase></code>.
- You can call it like this:
- </para>
- <para>
- <programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tie</phrase><phrase role="special">(</phrase> <phrase role="identifier">ec</phrase><phrase role="special">,</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="identifier">read_ec</phrase><phrase role="special">(</phrase> <phrase role="identifier">api</phrase><phrase role="special">);</phrase>
- </programlisting>
- </para>
- </section>
- <section id="fiber.callbacks.data_or_exception">
- <title><anchor id="Data_or_Exception"/><link linkend="fiber.callbacks.data_or_exception">Data
- or Exception</link></title>
- <para>
- But a more natural API for a function that obtains data is to return only
- the data on success, throwing an exception on error.
- </para>
- <para>
- As with <code><phrase role="identifier">write</phrase><phrase role="special">()</phrase></code>
- above, it’s certainly possible to code a <code><phrase role="identifier">read</phrase><phrase
- role="special">()</phrase></code> wrapper in terms of <code><phrase role="identifier">read_ec</phrase><phrase
- role="special">()</phrase></code>. But since a given application is unlikely
- to need both, let’s code <code><phrase role="identifier">read</phrase><phrase
- role="special">()</phrase></code> from scratch, leveraging <link linkend="promise_set_exception"><code>promise::set_exception()</code></link>:
- </para>
- <para>
- <programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">read</phrase><phrase role="special">(</phrase> <phrase role="identifier">AsyncAPI</phrase> <phrase role="special">&</phrase> <phrase role="identifier">api</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">promise</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></phrase> <phrase role="identifier">promise</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></phrase> <phrase role="identifier">future</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">get_future</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// Both 'promise' and 'future' will survive until our lambda has been</phrase>
- <phrase role="comment">// called.</phrase>
- <phrase role="preprocessor">#if</phrase> <phrase role="special">!</phrase> <phrase role="identifier">defined</phrase><phrase role="special">(</phrase><phrase role="identifier">BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES</phrase><phrase role="special">)</phrase>
- <phrase role="identifier">api</phrase><phrase role="special">.</phrase><phrase role="identifier">init_read</phrase><phrase role="special">([&</phrase><phrase role="identifier">promise</phrase><phrase role="special">](</phrase> <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">ec</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="keyword">mutable</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">data</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase> <phrase role="keyword">else</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">set_exception</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_exception_ptr</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">make_exception</phrase><phrase role="special">(</phrase><phrase role="string">"read"</phrase><phrase role="special">,</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">});</phrase>
- <phrase role="preprocessor">#else</phrase> <phrase role="comment">// defined(BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES)</phrase>
- <phrase role="identifier">api</phrase><phrase role="special">.</phrase><phrase role="identifier">init_read</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">bind</phrase><phrase role="special">([](</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">promise</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">promise</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">AsyncAPI</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">ec</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="keyword">mutable</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">data</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase> <phrase role="keyword">else</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">promise</phrase><phrase role="special">.</phrase><phrase role="identifier">set_exception</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_exception_ptr</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">make_exception</phrase><phrase role="special">(</phrase><phrase role="string">"read"</phrase><phrase role="special">,</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">},</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase> <phrase role="identifier">promise</phrase><phrase role="special">),</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">placeholders</phrase><phrase role="special">::</phrase><phrase role="identifier">_1</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">placeholders</phrase><phrase role="special">::</phrase><phrase role="identifier">_2</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="preprocessor">#endif</phrase> <phrase role="comment">// BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- <link linkend="future_get"><code>future::get()</code></link> will do the right thing, either returning <code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase></code>
- or throwing an exception.
- </para>
- </section>
- <section id="fiber.callbacks.success_error_virtual_methods">
- <title><link linkend="fiber.callbacks.success_error_virtual_methods">Success/Error
- Virtual Methods</link></title>
- <para>
- One classic approach to completion notification is to define an abstract
- base class with <code><phrase role="identifier">success</phrase><phrase role="special">()</phrase></code>
- and <code><phrase role="identifier">error</phrase><phrase role="special">()</phrase></code>
- methods. Code wishing to perform async I/O must derive a subclass, override
- each of these methods and pass the async operation a pointer to a subclass
- instance. The abstract base class might look like this:
- </para>
- <para>
- <programlisting><phrase role="comment">// every async operation receives a subclass instance of this abstract base</phrase>
- <phrase role="comment">// class through which to communicate its result</phrase>
- <phrase role="keyword">struct</phrase> <phrase role="identifier">Response</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special"><</phrase> <phrase role="identifier">Response</phrase> <phrase role="special">></phrase> <phrase role="identifier">ptr</phrase><phrase role="special">;</phrase>
- <phrase role="comment">// called if the operation succeeds</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">success</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- <phrase role="comment">// called if the operation fails</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">error</phrase><phrase role="special">(</phrase> <phrase role="identifier">AsyncAPIBase</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <para>
- Now the <code><phrase role="identifier">AsyncAPI</phrase></code> operation
- might look more like this:
- </para>
- <para>
- <programlisting><phrase role="comment">// derive Response subclass, instantiate, pass Response::ptr</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">init_read</phrase><phrase role="special">(</phrase> <phrase role="identifier">Response</phrase><phrase role="special">::</phrase><phrase role="identifier">ptr</phrase><phrase role="special">);</phrase>
- </programlisting>
- </para>
- <para>
- We can address this by writing a one-size-fits-all <code><phrase role="identifier">PromiseResponse</phrase></code>:
- </para>
- <para>
- <programlisting><phrase role="keyword">class</phrase> <phrase role="identifier">PromiseResponse</phrase><phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">Response</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="comment">// called if the operation succeeds</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">success</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">data</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">promise_</phrase><phrase role="special">.</phrase><phrase role="identifier">set_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">data</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// called if the operation fails</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">error</phrase><phrase role="special">(</phrase> <phrase role="identifier">AsyncAPIBase</phrase><phrase role="special">::</phrase><phrase role="identifier">errorcode</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">promise_</phrase><phrase role="special">.</phrase><phrase role="identifier">set_exception</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_exception_ptr</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">make_exception</phrase><phrase role="special">(</phrase><phrase role="string">"read"</phrase><phrase role="special">,</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></phrase> <phrase role="identifier">get_future</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">promise_</phrase><phrase role="special">.</phrase><phrase role="identifier">get_future</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">private</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">promise</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></phrase> <phrase role="identifier">promise_</phrase><phrase role="special">;</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <para>
- Now we can simply obtain the <code><phrase role="identifier">future</phrase><phrase
- role="special"><></phrase></code> from that <code><phrase role="identifier">PromiseResponse</phrase></code>
- and wait on its <code><phrase role="identifier">get</phrase><phrase role="special">()</phrase></code>:
- </para>
- <para>
- <programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">read</phrase><phrase role="special">(</phrase> <phrase role="identifier">AsyncAPI</phrase> <phrase role="special">&</phrase> <phrase role="identifier">api</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// Because init_read() requires a shared_ptr, we must allocate our</phrase>
- <phrase role="comment">// ResponsePromise on the heap, even though we know its lifespan.</phrase>
- <phrase role="keyword">auto</phrase> <phrase role="identifier">promisep</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special"><</phrase> <phrase role="identifier">PromiseResponse</phrase> <phrase role="special">>()</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></phrase> <phrase role="identifier">future</phrase><phrase role="special">(</phrase> <phrase role="identifier">promisep</phrase><phrase role="special">-></phrase><phrase role="identifier">get_future</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// Both 'promisep' and 'future' will survive until our lambda has been</phrase>
- <phrase role="comment">// called.</phrase>
- <phrase role="identifier">api</phrase><phrase role="special">.</phrase><phrase role="identifier">init_read</phrase><phrase role="special">(</phrase> <phrase role="identifier">promisep</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- The source code above is found in <ulink url="../../examples/adapt_callbacks.cpp">adapt_callbacks.cpp</ulink>
- and <ulink url="../../examples/adapt_method_calls.cpp">adapt_method_calls.cpp</ulink>.
- </para>
- </section>
- <section id="fiber.callbacks.then_there_s____boost_asio__">
- <title><anchor id="callbacks_asio"/><link linkend="fiber.callbacks.then_there_s____boost_asio__">Then
- There’s <ulink url="http://www.boost.org/doc/libs/release/libs/asio/index.html">Boost.Asio</ulink></link></title>
- <para>
- Since the simplest form of Boost.Asio asynchronous operation completion token
- is a callback function, we could apply the same tactics for Asio as for our
- hypothetical <code><phrase role="identifier">AsyncAPI</phrase></code> asynchronous
- operations.
- </para>
- <para>
- Fortunately we need not. Boost.Asio incorporates a mechanism<footnote id="fiber.callbacks.then_there_s____boost_asio__.f0">
- <para>
- This mechanism has been proposed as a conventional way to allow the caller
- of an arbitrary async function to specify completion handling: <ulink url="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4045.pdf">N4045</ulink>.
- </para>
- </footnote> by which the caller can customize the notification behavior of
- any async operation. Therefore we can construct a <emphasis>completion token</emphasis>
- which, when passed to a <ulink url="http://www.boost.org/doc/libs/release/libs/asio/index.html">Boost.Asio</ulink>
- async operation, requests blocking for the calling fiber.
- </para>
- <para>
- A typical Asio async function might look something like this:<footnote id="fiber.callbacks.then_there_s____boost_asio__.f1">
- <para>
- per <ulink url="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4045.pdf">N4045</ulink>
- </para>
- </footnote>
- </para>
- <programlisting><phrase role="keyword">template</phrase> <phrase role="special"><</phrase> <phrase role="special">...,</phrase> <phrase role="keyword">class</phrase> <phrase role="identifier">CompletionToken</phrase> <phrase role="special">></phrase>
- <emphasis>deduced_return_type</emphasis>
- <phrase role="identifier">async_something</phrase><phrase role="special">(</phrase> <phrase role="special">...</phrase> <phrase role="special">,</phrase> <phrase role="identifier">CompletionToken</phrase><phrase role="special">&&</phrase> <phrase role="identifier">token</phrase><phrase role="special">)</phrase>
- <phrase role="special">{</phrase>
- <phrase role="comment">// construct handler_type instance from CompletionToken</phrase>
- <phrase role="identifier">handler_type</phrase><phrase role="special"><</phrase><phrase role="identifier">CompletionToken</phrase><phrase role="special">,</phrase> <phrase role="special">...>::</phrase><phrase role="identifier">type</phrase> <emphasis role="bold"><!--quickbook-escape-prefix--><code><!--quickbook-escape-postfix-->handler(token)<!--quickbook-escape-prefix--></code><!--quickbook-escape-postfix--></emphasis><phrase role="special">;</phrase>
- <phrase role="comment">// construct async_result instance from handler_type</phrase>
- <phrase role="identifier">async_result</phrase><phrase role="special"><</phrase><phrase role="keyword">decltype</phrase><phrase role="special">(</phrase><phrase role="identifier">handler</phrase><phrase role="special">)></phrase> <emphasis role="bold"><!--quickbook-escape-prefix--><code><!--quickbook-escape-postfix-->result(handler)<!--quickbook-escape-prefix--></code><!--quickbook-escape-postfix--></emphasis><phrase role="special">;</phrase>
- <phrase role="comment">// ... arrange to call handler on completion ...</phrase>
- <phrase role="comment">// ... initiate actual I/O operation ...</phrase>
- <phrase role="keyword">return</phrase> <emphasis role="bold"><!--quickbook-escape-prefix--><code><!--quickbook-escape-postfix-->result.get()<!--quickbook-escape-prefix--></code><!--quickbook-escape-postfix--></emphasis><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- <para>
- We will engage that mechanism, which is based on specializing Asio’s <code><phrase
- role="identifier">handler_type</phrase><phrase role="special"><></phrase></code>
- template for the <code><phrase role="identifier">CompletionToken</phrase></code>
- type and the signature of the specific callback. The remainder of this discussion
- will refer back to <code><phrase role="identifier">async_something</phrase><phrase
- role="special">()</phrase></code> as the Asio async function under consideration.
- </para>
- <para>
- The implementation described below uses lower-level facilities than <code><phrase
- role="identifier">promise</phrase></code> and <code><phrase role="identifier">future</phrase></code>
- because the <code><phrase role="identifier">promise</phrase></code> mechanism
- interacts badly with <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/stop.html"><code><phrase
- role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
- role="identifier">stop</phrase><phrase role="special">()</phrase></code></ulink>.
- It produces <code><phrase role="identifier">broken_promise</phrase></code>
- exceptions.
- </para>
- <para>
- <code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase
- role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
- role="identifier">yield</phrase></code> is a completion token of this kind.
- <code><phrase role="identifier">yield</phrase></code> is an instance of
- <code><phrase role="identifier">yield_t</phrase></code>:
- </para>
- <para>
- <programlisting><phrase role="keyword">class</phrase> <phrase role="identifier">yield_t</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">yield_t</phrase><phrase role="special">()</phrase> <phrase role="special">=</phrase> <phrase role="keyword">default</phrase><phrase role="special">;</phrase>
- <phrase role="comment">/**
- * @code
- * static yield_t yield;
- * boost::system::error_code myec;
- * func(yield[myec]);
- * @endcode
- * @c yield[myec] returns an instance of @c yield_t whose @c ec_ points
- * to @c myec. The expression @c yield[myec] "binds" @c myec to that
- * (anonymous) @c yield_t instance, instructing @c func() to store any
- * @c error_code it might produce into @c myec rather than throwing @c
- * boost::system::system_error.
- */</phrase>
- <phrase role="identifier">yield_t</phrase> <phrase role="keyword">operator</phrase><phrase role="special">[](</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase> <phrase role="special">&</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">yield_t</phrase> <phrase role="identifier">tmp</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">tmp</phrase><phrase role="special">.</phrase><phrase role="identifier">ec_</phrase> <phrase role="special">=</phrase> <phrase role="special">&</phrase> <phrase role="identifier">ec</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">tmp</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">//private:</phrase>
- <phrase role="comment">// ptr to bound error_code instance if any</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase> <phrase role="special">*</phrase> <phrase role="identifier">ec_</phrase><phrase role="special">{</phrase> <phrase role="keyword">nullptr</phrase> <phrase role="special">};</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <para>
- <code><phrase role="identifier">yield_t</phrase></code> is in fact only a
- placeholder, a way to trigger Boost.Asio customization. It can bind a <ulink
- url="http://www.boost.org/doc/libs/release/libs/system/doc/reference.html#Class-error_code"><code><phrase
- role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">system</phrase><phrase role="special">::</phrase><phrase
- role="identifier">error_code</phrase></code></ulink> for use by the actual
- handler.
- </para>
- <para>
- <code><phrase role="identifier">yield</phrase></code> is declared as:
- </para>
- <para>
- <programlisting><phrase role="comment">// canonical instance</phrase>
- <phrase role="keyword">thread_local</phrase> <phrase role="identifier">yield_t</phrase> <phrase role="identifier">yield</phrase><phrase role="special">{};</phrase>
- </programlisting>
- </para>
- <para>
- Asio customization is engaged by specializing <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/handler_type.html"><code><phrase
- role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
- role="identifier">handler_type</phrase><phrase role="special"><></phrase></code></ulink>
- for <code><phrase role="identifier">yield_t</phrase></code>:
- </para>
- <para>
- <programlisting><phrase role="comment">// Handler type specialisation for fibers::asio::yield.</phrase>
- <phrase role="comment">// When 'yield' is passed as a completion handler which accepts only</phrase>
- <phrase role="comment">// error_code, use yield_handler<void>. yield_handler will take care of the</phrase>
- <phrase role="comment">// error_code one way or another.</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">ReturnType</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">struct</phrase> <phrase role="identifier">handler_type</phrase><phrase role="special"><</phrase> <phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">yield_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">ReturnType</phrase><phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase><phrase role="special">)</phrase> <phrase role="special">></phrase>
- <phrase role="special">{</phrase> <phrase role="keyword">typedef</phrase> <phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">yield_handler</phrase><phrase role="special"><</phrase> <phrase role="keyword">void</phrase> <phrase role="special">></phrase> <phrase role="identifier">type</phrase><phrase role="special">;</phrase> <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <para>
- (There are actually four different specializations in <ulink url="../../examples/asio/detail/yield.hpp">detail/yield.hpp</ulink>,
- one for each of the four Asio async callback signatures we expect.)
- </para>
- <para>
- The above directs Asio to use <code><phrase role="identifier">yield_handler</phrase></code>
- as the actual handler for an async operation to which <code><phrase role="identifier">yield</phrase></code>
- is passed. There’s a generic <code><phrase role="identifier">yield_handler</phrase><phrase
- role="special"><</phrase><phrase role="identifier">T</phrase><phrase role="special">></phrase></code>
- implementation and a <code><phrase role="identifier">yield_handler</phrase><phrase
- role="special"><</phrase><phrase role="keyword">void</phrase><phrase role="special">></phrase></code>
- specialization. Let’s start with the <code><phrase role="special"><</phrase><phrase
- role="keyword">void</phrase><phrase role="special">></phrase></code> specialization:
- </para>
- <para>
- <programlisting><phrase role="comment">// yield_handler<void> is like yield_handler<T> without value_. In fact it's</phrase>
- <phrase role="comment">// just like yield_handler_base.</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><></phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">yield_handler</phrase><phrase role="special"><</phrase> <phrase role="keyword">void</phrase> <phrase role="special">>:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">yield_handler_base</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="keyword">explicit</phrase> <phrase role="identifier">yield_handler</phrase><phrase role="special">(</phrase> <phrase role="identifier">yield_t</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">y</phrase><phrase role="special">)</phrase> <phrase role="special">:</phrase>
- <phrase role="identifier">yield_handler_base</phrase><phrase role="special">{</phrase> <phrase role="identifier">y</phrase> <phrase role="special">}</phrase> <phrase role="special">{</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// nullary completion callback</phrase>
- <phrase role="keyword">void</phrase> <phrase role="keyword">operator</phrase><phrase role="special">()()</phrase> <phrase role="special">{</phrase>
- <phrase role="special">(</phrase> <phrase role="special">*</phrase> <phrase role="keyword">this</phrase><phrase role="special">)(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// inherit operator()(error_code) overload from base class</phrase>
- <phrase role="keyword">using</phrase> <phrase role="identifier">yield_handler_base</phrase><phrase role="special">::</phrase><phrase role="keyword">operator</phrase><phrase role="special">();</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <para>
- <code><phrase role="identifier">async_something</phrase><phrase role="special">()</phrase></code>,
- having consulted the <code><phrase role="identifier">handler_type</phrase><phrase
- role="special"><></phrase></code> traits specialization, instantiates
- a <code><phrase role="identifier">yield_handler</phrase><phrase role="special"><</phrase><phrase
- role="keyword">void</phrase><phrase role="special">></phrase></code> to
- be passed as the actual callback for the async operation. <code><phrase role="identifier">yield_handler</phrase></code>’s
- constructor accepts the <code><phrase role="identifier">yield_t</phrase></code>
- instance (the <code><phrase role="identifier">yield</phrase></code> object
- passed to the async function) and passes it along to <code><phrase role="identifier">yield_handler_base</phrase></code>:
- </para>
- <para>
- <programlisting><phrase role="comment">// This class encapsulates common elements between yield_handler<T> (capturing</phrase>
- <phrase role="comment">// a value to return from asio async function) and yield_handler<void> (no</phrase>
- <phrase role="comment">// such value). See yield_handler<T> and its <void> specialization below. Both</phrase>
- <phrase role="comment">// yield_handler<T> and yield_handler<void> are passed by value through</phrase>
- <phrase role="comment">// various layers of asio functions. In other words, they're potentially</phrase>
- <phrase role="comment">// copied multiple times. So key data such as the yield_completion instance</phrase>
- <phrase role="comment">// must be stored in our async_result<yield_handler<>> specialization, which</phrase>
- <phrase role="comment">// should be instantiated only once.</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">yield_handler_base</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">yield_handler_base</phrase><phrase role="special">(</phrase> <phrase role="identifier">yield_t</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">y</phrase><phrase role="special">)</phrase> <phrase role="special">:</phrase>
- <phrase role="comment">// capture the context* associated with the running fiber</phrase>
- <phrase role="identifier">ctx_</phrase><phrase role="special">{</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase><phrase role="special">::</phrase><phrase role="identifier">active</phrase><phrase role="special">()</phrase> <phrase role="special">},</phrase>
- <phrase role="comment">// capture the passed yield_t</phrase>
- <phrase role="identifier">yt_</phrase><phrase role="special">(</phrase> <phrase role="identifier">y</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// completion callback passing only (error_code)</phrase>
- <phrase role="keyword">void</phrase> <phrase role="keyword">operator</phrase><phrase role="special">()(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">BOOST_ASSERT_MSG</phrase><phrase role="special">(</phrase> <phrase role="identifier">ycomp_</phrase><phrase role="special">,</phrase>
- <phrase role="string">"Must inject yield_completion* "</phrase>
- <phrase role="string">"before calling yield_handler_base::operator()()"</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">BOOST_ASSERT_MSG</phrase><phrase role="special">(</phrase> <phrase role="identifier">yt_</phrase><phrase role="special">.</phrase><phrase role="identifier">ec_</phrase><phrase role="special">,</phrase>
- <phrase role="string">"Must inject boost::system::error_code* "</phrase>
- <phrase role="string">"before calling yield_handler_base::operator()()"</phrase><phrase role="special">);</phrase>
- <phrase role="comment">// If originating fiber is busy testing state_ flag, wait until it</phrase>
- <phrase role="comment">// has observed (completed != state_).</phrase>
- <phrase role="identifier">yield_completion</phrase><phrase role="special">::</phrase><phrase role="identifier">lock_t</phrase> <phrase role="identifier">lk</phrase><phrase role="special">{</phrase> <phrase role="identifier">ycomp_</phrase><phrase role="special">-></phrase><phrase role="identifier">mtx_</phrase> <phrase role="special">};</phrase>
- <phrase role="identifier">yield_completion</phrase><phrase role="special">::</phrase><phrase role="identifier">state_t</phrase> <phrase role="identifier">state</phrase> <phrase role="special">=</phrase> <phrase role="identifier">ycomp_</phrase><phrase role="special">-></phrase><phrase role="identifier">state_</phrase><phrase role="special">;</phrase>
- <phrase role="comment">// Notify a subsequent yield_completion::wait() call that it need not</phrase>
- <phrase role="comment">// suspend.</phrase>
- <phrase role="identifier">ycomp_</phrase><phrase role="special">-></phrase><phrase role="identifier">state_</phrase> <phrase role="special">=</phrase> <phrase role="identifier">yield_completion</phrase><phrase role="special">::</phrase><phrase role="identifier">complete</phrase><phrase role="special">;</phrase>
- <phrase role="comment">// set the error_code bound by yield_t</phrase>
- <phrase role="special">*</phrase> <phrase role="identifier">yt_</phrase><phrase role="special">.</phrase><phrase role="identifier">ec_</phrase> <phrase role="special">=</phrase> <phrase role="identifier">ec</phrase><phrase role="special">;</phrase>
- <phrase role="comment">// unlock the lock that protects state_</phrase>
- <phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
- <phrase role="comment">// If ctx_ is still active, e.g. because the async operation</phrase>
- <phrase role="comment">// immediately called its callback (this method!) before the asio</phrase>
- <phrase role="comment">// async function called async_result_base::get(), we must not set it</phrase>
- <phrase role="comment">// ready.</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">yield_completion</phrase><phrase role="special">::</phrase><phrase role="identifier">waiting</phrase> <phrase role="special">==</phrase> <phrase role="identifier">state</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// wake the fiber</phrase>
- <phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase><phrase role="special">::</phrase><phrase role="identifier">active</phrase><phrase role="special">()-></phrase><phrase role="identifier">schedule</phrase><phrase role="special">(</phrase> <phrase role="identifier">ctx_</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">//private:</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">ctx_</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">yield_t</phrase> <phrase role="identifier">yt_</phrase><phrase role="special">;</phrase>
- <phrase role="comment">// We depend on this pointer to yield_completion, which will be injected</phrase>
- <phrase role="comment">// by async_result.</phrase>
- <phrase role="identifier">yield_completion</phrase><phrase role="special">::</phrase><phrase role="identifier">ptr_t</phrase> <phrase role="identifier">ycomp_</phrase><phrase role="special">{};</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <para>
- <code><phrase role="identifier">yield_handler_base</phrase></code> stores
- a copy of the <code><phrase role="identifier">yield_t</phrase></code> instance
- — which, as shown above, contains only an <code><phrase role="identifier">error_code</phrase><phrase
- role="special">*</phrase></code>. It also captures the <link linkend="class_context"><code>context</code></link>*
- for the currently-running fiber by calling <link linkend="context_active"><code>context::active()</code></link>.
- </para>
- <para>
- You will notice that <code><phrase role="identifier">yield_handler_base</phrase></code>
- has one more data member (<code><phrase role="identifier">ycomp_</phrase></code>)
- that is initialized to <code><phrase role="keyword">nullptr</phrase></code>
- by its constructor — though its <code><phrase role="keyword">operator</phrase><phrase
- role="special">()()</phrase></code> method relies on <code><phrase role="identifier">ycomp_</phrase></code>
- being non-null. More on this in a moment.
- </para>
- <para>
- Having constructed the <code><phrase role="identifier">yield_handler</phrase><phrase
- role="special"><</phrase><phrase role="keyword">void</phrase><phrase role="special">></phrase></code>
- instance, <code><phrase role="identifier">async_something</phrase><phrase
- role="special">()</phrase></code> goes on to construct an <code><phrase role="identifier">async_result</phrase></code>
- specialized for the <code><phrase role="identifier">handler_type</phrase><phrase
- role="special"><>::</phrase><phrase role="identifier">type</phrase></code>:
- in this case, <code><phrase role="identifier">async_result</phrase><phrase
- role="special"><</phrase><phrase role="identifier">yield_handler</phrase><phrase
- role="special"><</phrase><phrase role="keyword">void</phrase><phrase role="special">>></phrase></code>.
- It passes the <code><phrase role="identifier">yield_handler</phrase><phrase
- role="special"><</phrase><phrase role="keyword">void</phrase><phrase role="special">></phrase></code>
- instance to the new <code><phrase role="identifier">async_result</phrase></code>
- instance.
- </para>
- <para>
- <programlisting><phrase role="comment">// Without the need to handle a passed value, our yield_handler<void></phrase>
- <phrase role="comment">// specialization is just like async_result_base.</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><></phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">async_result</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">yield_handler</phrase><phrase role="special"><</phrase> <phrase role="keyword">void</phrase> <phrase role="special">></phrase> <phrase role="special">></phrase> <phrase role="special">:</phrase>
- <phrase role="keyword">public</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">async_result_base</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">type</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">explicit</phrase> <phrase role="identifier">async_result</phrase><phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">yield_handler</phrase><phrase role="special"><</phrase> <phrase role="keyword">void</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">h</phrase><phrase role="special">):</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">async_result_base</phrase><phrase role="special">{</phrase> <phrase role="identifier">h</phrase> <phrase role="special">}</phrase> <phrase role="special">{</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <para>
- Naturally that leads us straight to <code><phrase role="identifier">async_result_base</phrase></code>:
- </para>
- <para>
- <programlisting><phrase role="comment">// Factor out commonality between async_result<yield_handler<T>> and</phrase>
- <phrase role="comment">// async_result<yield_handler<void>></phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">async_result_base</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="keyword">explicit</phrase> <phrase role="identifier">async_result_base</phrase><phrase role="special">(</phrase> <phrase role="identifier">yield_handler_base</phrase> <phrase role="special">&</phrase> <phrase role="identifier">h</phrase><phrase role="special">)</phrase> <phrase role="special">:</phrase>
- <phrase role="identifier">ycomp_</phrase><phrase role="special">{</phrase> <phrase role="keyword">new</phrase> <phrase role="identifier">yield_completion</phrase><phrase role="special">{}</phrase> <phrase role="special">}</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// Inject ptr to our yield_completion instance into this</phrase>
- <phrase role="comment">// yield_handler<>.</phrase>
- <phrase role="identifier">h</phrase><phrase role="special">.</phrase><phrase role="identifier">ycomp_</phrase> <phrase role="special">=</phrase> <phrase role="keyword">this</phrase><phrase role="special">-></phrase><phrase role="identifier">ycomp_</phrase><phrase role="special">;</phrase>
- <phrase role="comment">// if yield_t didn't bind an error_code, make yield_handler_base's</phrase>
- <phrase role="comment">// error_code* point to an error_code local to this object so</phrase>
- <phrase role="comment">// yield_handler_base::operator() can unconditionally store through</phrase>
- <phrase role="comment">// its error_code*</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">h</phrase><phrase role="special">.</phrase><phrase role="identifier">yt_</phrase><phrase role="special">.</phrase><phrase role="identifier">ec_</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">h</phrase><phrase role="special">.</phrase><phrase role="identifier">yt_</phrase><phrase role="special">.</phrase><phrase role="identifier">ec_</phrase> <phrase role="special">=</phrase> <phrase role="special">&</phrase> <phrase role="identifier">ec_</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">get</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// Unless yield_handler_base::operator() has already been called,</phrase>
- <phrase role="comment">// suspend the calling fiber until that call.</phrase>
- <phrase role="identifier">ycomp_</phrase><phrase role="special">-></phrase><phrase role="identifier">wait</phrase><phrase role="special">();</phrase>
- <phrase role="comment">// The only way our own ec_ member could have a non-default value is</phrase>
- <phrase role="comment">// if our yield_handler did not have a bound error_code AND the</phrase>
- <phrase role="comment">// completion callback passed a non-default error_code.</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">ec_</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">throw_exception</phrase><phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">system_error</phrase><phrase role="special">{</phrase> <phrase role="identifier">ec_</phrase> <phrase role="special">}</phrase> <phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">private</phrase><phrase role="special">:</phrase>
- <phrase role="comment">// If yield_t does not bind an error_code instance, store into here.</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase> <phrase role="identifier">ec_</phrase><phrase role="special">{};</phrase>
- <phrase role="identifier">yield_completion</phrase><phrase role="special">::</phrase><phrase role="identifier">ptr_t</phrase> <phrase role="identifier">ycomp_</phrase><phrase role="special">;</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <para>
- This is how <code><phrase role="identifier">yield_handler_base</phrase><phrase
- role="special">::</phrase><phrase role="identifier">ycomp_</phrase></code>
- becomes non-null: <code><phrase role="identifier">async_result_base</phrase></code>’s
- constructor injects a pointer back to its own <code><phrase role="identifier">yield_completion</phrase></code>
- member.
- </para>
- <para>
- Recall that the canonical <code><phrase role="identifier">yield_t</phrase></code>
- instance <code><phrase role="identifier">yield</phrase></code> initializes
- its <code><phrase role="identifier">error_code</phrase><phrase role="special">*</phrase></code>
- member <code><phrase role="identifier">ec_</phrase></code> to <code><phrase
- role="keyword">nullptr</phrase></code>. If this instance is passed to <code><phrase
- role="identifier">async_something</phrase><phrase role="special">()</phrase></code>
- (<code><phrase role="identifier">ec_</phrase></code> is still <code><phrase
- role="keyword">nullptr</phrase></code>), the copy stored in <code><phrase
- role="identifier">yield_handler_base</phrase></code> will likewise have null
- <code><phrase role="identifier">ec_</phrase></code>. <code><phrase role="identifier">async_result_base</phrase></code>’s
- constructor sets <code><phrase role="identifier">yield_handler_base</phrase></code>’s
- <code><phrase role="identifier">yield_t</phrase></code>’s <code><phrase role="identifier">ec_</phrase></code>
- member to point to its own <code><phrase role="identifier">error_code</phrase></code>
- member.
- </para>
- <para>
- The stage is now set. <code><phrase role="identifier">async_something</phrase><phrase
- role="special">()</phrase></code> initiates the actual async operation, arranging
- to call its <code><phrase role="identifier">yield_handler</phrase><phrase
- role="special"><</phrase><phrase role="keyword">void</phrase><phrase role="special">></phrase></code>
- instance on completion. Let’s say, for the sake of argument, that the actual
- async operation’s callback has signature <code><phrase role="keyword">void</phrase><phrase
- role="special">(</phrase><phrase role="identifier">error_code</phrase><phrase
- role="special">)</phrase></code>.
- </para>
- <para>
- But since it’s an async operation, control returns at once to <code><phrase
- role="identifier">async_something</phrase><phrase role="special">()</phrase></code>.
- <code><phrase role="identifier">async_something</phrase><phrase role="special">()</phrase></code>
- calls <code><phrase role="identifier">async_result</phrase><phrase role="special"><</phrase><phrase
- role="identifier">yield_handler</phrase><phrase role="special"><</phrase><phrase
- role="keyword">void</phrase><phrase role="special">>>::</phrase><phrase
- role="identifier">get</phrase><phrase role="special">()</phrase></code>,
- and will return its return value.
- </para>
- <para>
- <code><phrase role="identifier">async_result</phrase><phrase role="special"><</phrase><phrase
- role="identifier">yield_handler</phrase><phrase role="special"><</phrase><phrase
- role="keyword">void</phrase><phrase role="special">>>::</phrase><phrase
- role="identifier">get</phrase><phrase role="special">()</phrase></code> inherits
- <code><phrase role="identifier">async_result_base</phrase><phrase role="special">::</phrase><phrase
- role="identifier">get</phrase><phrase role="special">()</phrase></code>.
- </para>
- <para>
- <code><phrase role="identifier">async_result_base</phrase><phrase role="special">::</phrase><phrase
- role="identifier">get</phrase><phrase role="special">()</phrase></code> immediately
- calls <code><phrase role="identifier">yield_completion</phrase><phrase role="special">::</phrase><phrase
- role="identifier">wait</phrase><phrase role="special">()</phrase></code>.
- </para>
- <para>
- <programlisting><phrase role="comment">// Bundle a completion bool flag with a spinlock to protect it.</phrase>
- <phrase role="keyword">struct</phrase> <phrase role="identifier">yield_completion</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">enum</phrase> <phrase role="identifier">state_t</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">init</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">waiting</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">complete</phrase>
- <phrase role="special">};</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">spinlock</phrase> <phrase role="identifier">mutex_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special"><</phrase> <phrase role="identifier">mutex_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">lock_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">intrusive_ptr</phrase><phrase role="special"><</phrase> <phrase role="identifier">yield_completion</phrase> <phrase role="special">></phrase> <phrase role="identifier">ptr_t</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">atomic</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">use_count_</phrase><phrase role="special">{</phrase> <phrase role="number">0</phrase> <phrase role="special">};</phrase>
- <phrase role="identifier">mutex_t</phrase> <phrase role="identifier">mtx_</phrase><phrase role="special">{};</phrase>
- <phrase role="identifier">state_t</phrase> <phrase role="identifier">state_</phrase><phrase role="special">{</phrase> <phrase role="identifier">init</phrase> <phrase role="special">};</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// yield_handler_base::operator()() will set state_ `complete` and</phrase>
- <phrase role="comment">// attempt to wake a suspended fiber. It would be Bad if that call</phrase>
- <phrase role="comment">// happened between our detecting (complete != state_) and suspending.</phrase>
- <phrase role="identifier">lock_t</phrase> <phrase role="identifier">lk</phrase><phrase role="special">{</phrase> <phrase role="identifier">mtx_</phrase> <phrase role="special">};</phrase>
- <phrase role="comment">// If state_ is already set, we're done here: don't suspend.</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">complete</phrase> <phrase role="special">!=</phrase> <phrase role="identifier">state_</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">state_</phrase> <phrase role="special">=</phrase> <phrase role="identifier">waiting</phrase><phrase role="special">;</phrase>
- <phrase role="comment">// suspend(unique_lock<spinlock>) unlocks the lock in the act of</phrase>
- <phrase role="comment">// resuming another fiber</phrase>
- <phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase><phrase role="special">::</phrase><phrase role="identifier">active</phrase><phrase role="special">()-></phrase><phrase role="identifier">suspend</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">friend</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">intrusive_ptr_add_ref</phrase><phrase role="special">(</phrase> <phrase role="identifier">yield_completion</phrase> <phrase role="special">*</phrase> <phrase role="identifier">yc</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">BOOST_ASSERT</phrase><phrase role="special">(</phrase> <phrase role="keyword">nullptr</phrase> <phrase role="special">!=</phrase> <phrase role="identifier">yc</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">yc</phrase><phrase role="special">-></phrase><phrase role="identifier">use_count_</phrase><phrase role="special">.</phrase><phrase role="identifier">fetch_add</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">memory_order_relaxed</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">friend</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">intrusive_ptr_release</phrase><phrase role="special">(</phrase> <phrase role="identifier">yield_completion</phrase> <phrase role="special">*</phrase> <phrase role="identifier">yc</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">BOOST_ASSERT</phrase><phrase role="special">(</phrase> <phrase role="keyword">nullptr</phrase> <phrase role="special">!=</phrase> <phrase role="identifier">yc</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="number">1</phrase> <phrase role="special">==</phrase> <phrase role="identifier">yc</phrase><phrase role="special">-></phrase><phrase role="identifier">use_count_</phrase><phrase role="special">.</phrase><phrase role="identifier">fetch_sub</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">memory_order_release</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">atomic_thread_fence</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">memory_order_acquire</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">delete</phrase> <phrase role="identifier">yc</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <para>
- Supposing that the pending async operation has not yet completed, <code><phrase
- role="identifier">yield_completion</phrase><phrase role="special">::</phrase><phrase
- role="identifier">completed_</phrase></code> will still be <code><phrase
- role="keyword">false</phrase></code>, and <code><phrase role="identifier">wait</phrase><phrase
- role="special">()</phrase></code> will call <link linkend="context_suspend"><code>context::suspend()</code></link> on
- the currently-running fiber.
- </para>
- <para>
- Other fibers will now have a chance to run.
- </para>
- <para>
- Some time later, the async operation completes. It calls <code><phrase role="identifier">yield_handler</phrase><phrase
- role="special"><</phrase><phrase role="keyword">void</phrase><phrase role="special">>::</phrase><phrase
- role="keyword">operator</phrase><phrase role="special">()(</phrase><phrase
- role="identifier">error_code</phrase> <phrase role="keyword">const</phrase><phrase
- role="special">&)</phrase></code> with an <code><phrase role="identifier">error_code</phrase></code>
- indicating either success or failure. We’ll consider both cases.
- </para>
- <para>
- <code><phrase role="identifier">yield_handler</phrase><phrase role="special"><</phrase><phrase
- role="keyword">void</phrase><phrase role="special">></phrase></code> explicitly
- inherits <code><phrase role="keyword">operator</phrase><phrase role="special">()(</phrase><phrase
- role="identifier">error_code</phrase> <phrase role="keyword">const</phrase><phrase
- role="special">&)</phrase></code> from <code><phrase role="identifier">yield_handler_base</phrase></code>.
- </para>
- <para>
- <code><phrase role="identifier">yield_handler_base</phrase><phrase role="special">::</phrase><phrase
- role="keyword">operator</phrase><phrase role="special">()(</phrase><phrase
- role="identifier">error_code</phrase> <phrase role="keyword">const</phrase><phrase
- role="special">&)</phrase></code> first sets <code><phrase role="identifier">yield_completion</phrase><phrase
- role="special">::</phrase><phrase role="identifier">completed_</phrase></code>
- <code><phrase role="keyword">true</phrase></code>. This way, if <code><phrase
- role="identifier">async_something</phrase><phrase role="special">()</phrase></code>’s
- async operation completes immediately — if <code><phrase role="identifier">yield_handler_base</phrase><phrase
- role="special">::</phrase><phrase role="keyword">operator</phrase><phrase
- role="special">()</phrase></code> is called even before <code><phrase role="identifier">async_result_base</phrase><phrase
- role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special">()</phrase></code>
- — the calling fiber will <emphasis>not</emphasis> suspend.
- </para>
- <para>
- The actual <code><phrase role="identifier">error_code</phrase></code> produced
- by the async operation is then stored through the stored <code><phrase role="identifier">yield_t</phrase><phrase
- role="special">::</phrase><phrase role="identifier">ec_</phrase></code> pointer.
- If <code><phrase role="identifier">async_something</phrase><phrase role="special">()</phrase></code>’s
- caller used (e.g.) <code><phrase role="identifier">yield</phrase><phrase
- role="special">[</phrase><phrase role="identifier">my_ec</phrase><phrase
- role="special">]</phrase></code> to bind a local <code><phrase role="identifier">error_code</phrase></code>
- instance, the actual <code><phrase role="identifier">error_code</phrase></code>
- value is stored into the caller’s variable. Otherwise, it is stored into
- <code><phrase role="identifier">async_result_base</phrase><phrase role="special">::</phrase><phrase
- role="identifier">ec_</phrase></code>.
- </para>
- <para>
- If the stored fiber context <code><phrase role="identifier">yield_handler_base</phrase><phrase
- role="special">::</phrase><phrase role="identifier">ctx_</phrase></code>
- is not already running, it is marked as ready to run by passing it to <link linkend="context_schedule"><code>context::schedule()</code></link>.
- Control then returns from <code><phrase role="identifier">yield_handler_base</phrase><phrase
- role="special">::</phrase><phrase role="keyword">operator</phrase><phrase
- role="special">()</phrase></code>: the callback is done.
- </para>
- <para>
- In due course, that fiber is resumed. Control returns from <link linkend="context_suspend"><code>context::suspend()</code></link> to
- <code><phrase role="identifier">yield_completion</phrase><phrase role="special">::</phrase><phrase
- role="identifier">wait</phrase><phrase role="special">()</phrase></code>,
- which returns to <code><phrase role="identifier">async_result_base</phrase><phrase
- role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special">()</phrase></code>.
- </para>
- <itemizedlist>
- <listitem>
- <simpara>
- If the original caller passed <code><phrase role="identifier">yield</phrase><phrase
- role="special">[</phrase><phrase role="identifier">my_ec</phrase><phrase
- role="special">]</phrase></code> to <code><phrase role="identifier">async_something</phrase><phrase
- role="special">()</phrase></code> to bind a local <code><phrase role="identifier">error_code</phrase></code>
- instance, then <code><phrase role="identifier">yield_handler_base</phrase><phrase
- role="special">::</phrase><phrase role="keyword">operator</phrase><phrase
- role="special">()</phrase></code> stored its <code><phrase role="identifier">error_code</phrase></code>
- to the caller’s <code><phrase role="identifier">my_ec</phrase></code>
- instance, leaving <code><phrase role="identifier">async_result_base</phrase><phrase
- role="special">::</phrase><phrase role="identifier">ec_</phrase></code>
- initialized to success.
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- If the original caller passed <code><phrase role="identifier">yield</phrase></code>
- to <code><phrase role="identifier">async_something</phrase><phrase role="special">()</phrase></code>
- without binding a local <code><phrase role="identifier">error_code</phrase></code>
- variable, then <code><phrase role="identifier">yield_handler_base</phrase><phrase
- role="special">::</phrase><phrase role="keyword">operator</phrase><phrase
- role="special">()</phrase></code> stored its <code><phrase role="identifier">error_code</phrase></code>
- into <code><phrase role="identifier">async_result_base</phrase><phrase
- role="special">::</phrase><phrase role="identifier">ec_</phrase></code>.
- If in fact that <code><phrase role="identifier">error_code</phrase></code>
- is success, then all is well.
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- Otherwise — the original caller did not bind a local <code><phrase role="identifier">error_code</phrase></code>
- and <code><phrase role="identifier">yield_handler_base</phrase><phrase
- role="special">::</phrase><phrase role="keyword">operator</phrase><phrase
- role="special">()</phrase></code> was called with an <code><phrase role="identifier">error_code</phrase></code>
- indicating error — <code><phrase role="identifier">async_result_base</phrase><phrase
- role="special">::</phrase><phrase role="identifier">get</phrase><phrase
- role="special">()</phrase></code> throws <code><phrase role="identifier">system_error</phrase></code>
- with that <code><phrase role="identifier">error_code</phrase></code>.
- </simpara>
- </listitem>
- </itemizedlist>
- <para>
- The case in which <code><phrase role="identifier">async_something</phrase><phrase
- role="special">()</phrase></code>’s completion callback has signature <code><phrase
- role="keyword">void</phrase><phrase role="special">()</phrase></code> is
- similar. <code><phrase role="identifier">yield_handler</phrase><phrase role="special"><</phrase><phrase
- role="keyword">void</phrase><phrase role="special">>::</phrase><phrase
- role="keyword">operator</phrase><phrase role="special">()()</phrase></code>
- invokes the machinery above with a <quote>success</quote> <code><phrase role="identifier">error_code</phrase></code>.
- </para>
- <para>
- A completion callback with signature <code><phrase role="keyword">void</phrase><phrase
- role="special">(</phrase><phrase role="identifier">error_code</phrase><phrase
- role="special">,</phrase> <phrase role="identifier">T</phrase><phrase role="special">)</phrase></code>
- (that is: in addition to <code><phrase role="identifier">error_code</phrase></code>,
- callback receives some data item) is handled somewhat differently. For this
- kind of signature, <code><phrase role="identifier">handler_type</phrase><phrase
- role="special"><>::</phrase><phrase role="identifier">type</phrase></code>
- specifies <code><phrase role="identifier">yield_handler</phrase><phrase role="special"><</phrase><phrase
- role="identifier">T</phrase><phrase role="special">></phrase></code> (for
- <code><phrase role="identifier">T</phrase></code> other than <code><phrase
- role="keyword">void</phrase></code>).
- </para>
- <para>
- A <code><phrase role="identifier">yield_handler</phrase><phrase role="special"><</phrase><phrase
- role="identifier">T</phrase><phrase role="special">></phrase></code> reserves
- a <code><phrase role="identifier">value_</phrase></code> pointer to a value
- of type <code><phrase role="identifier">T</phrase></code>:
- </para>
- <para>
- <programlisting><phrase role="comment">// asio uses handler_type<completion token type, signature>::type to decide</phrase>
- <phrase role="comment">// what to instantiate as the actual handler. Below, we specialize</phrase>
- <phrase role="comment">// handler_type< yield_t, ... > to indicate yield_handler<>. So when you pass</phrase>
- <phrase role="comment">// an instance of yield_t as an asio completion token, asio selects</phrase>
- <phrase role="comment">// yield_handler<> as the actual handler class.</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">yield_handler</phrase><phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">yield_handler_base</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="comment">// asio passes the completion token to the handler constructor</phrase>
- <phrase role="keyword">explicit</phrase> <phrase role="identifier">yield_handler</phrase><phrase role="special">(</phrase> <phrase role="identifier">yield_t</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">y</phrase><phrase role="special">)</phrase> <phrase role="special">:</phrase>
- <phrase role="identifier">yield_handler_base</phrase><phrase role="special">{</phrase> <phrase role="identifier">y</phrase> <phrase role="special">}</phrase> <phrase role="special">{</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// completion callback passing only value (T)</phrase>
- <phrase role="keyword">void</phrase> <phrase role="keyword">operator</phrase><phrase role="special">()(</phrase> <phrase role="identifier">T</phrase> <phrase role="identifier">t</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// just like callback passing success error_code</phrase>
- <phrase role="special">(*</phrase><phrase role="keyword">this</phrase><phrase role="special">)(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase><phrase role="special">(),</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase><phrase role="identifier">t</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// completion callback passing (error_code, T)</phrase>
- <phrase role="keyword">void</phrase> <phrase role="keyword">operator</phrase><phrase role="special">()(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">ec</phrase><phrase role="special">,</phrase> <phrase role="identifier">T</phrase> <phrase role="identifier">t</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">BOOST_ASSERT_MSG</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_</phrase><phrase role="special">,</phrase>
- <phrase role="string">"Must inject value ptr "</phrase>
- <phrase role="string">"before caling yield_handler<T>::operator()()"</phrase><phrase role="special">);</phrase>
- <phrase role="comment">// move the value to async_result<> instance BEFORE waking up a</phrase>
- <phrase role="comment">// suspended fiber</phrase>
- <phrase role="special">*</phrase> <phrase role="identifier">value_</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase> <phrase role="identifier">t</phrase><phrase role="special">);</phrase>
- <phrase role="comment">// forward the call to base-class completion handler</phrase>
- <phrase role="identifier">yield_handler_base</phrase><phrase role="special">::</phrase><phrase role="keyword">operator</phrase><phrase role="special">()(</phrase> <phrase role="identifier">ec</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">//private:</phrase>
- <phrase role="comment">// pointer to destination for eventual value</phrase>
- <phrase role="comment">// this must be injected by async_result before operator()() is called</phrase>
- <phrase role="identifier">T</phrase> <phrase role="special">*</phrase> <phrase role="identifier">value_</phrase><phrase role="special">{</phrase> <phrase role="keyword">nullptr</phrase> <phrase role="special">};</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <para>
- This pointer is initialized to <code><phrase role="keyword">nullptr</phrase></code>.
- </para>
- <para>
- When <code><phrase role="identifier">async_something</phrase><phrase role="special">()</phrase></code>
- instantiates <code><phrase role="identifier">async_result</phrase><phrase
- role="special"><</phrase><phrase role="identifier">yield_handler</phrase><phrase
- role="special"><</phrase><phrase role="identifier">T</phrase><phrase role="special">>></phrase></code>:
- </para>
- <para>
- <programlisting><phrase role="comment">// asio constructs an async_result<> instance from the yield_handler specified</phrase>
- <phrase role="comment">// by handler_type<>::type. A particular asio async method constructs the</phrase>
- <phrase role="comment">// yield_handler, constructs this async_result specialization from it, then</phrase>
- <phrase role="comment">// returns the result of calling its get() method.</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">async_result</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">yield_handler</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">></phrase> <phrase role="special">:</phrase>
- <phrase role="keyword">public</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">async_result_base</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="comment">// type returned by get()</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">T</phrase> <phrase role="identifier">type</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">explicit</phrase> <phrase role="identifier">async_result</phrase><phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">yield_handler</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">h</phrase><phrase role="special">)</phrase> <phrase role="special">:</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">async_result_base</phrase><phrase role="special">{</phrase> <phrase role="identifier">h</phrase> <phrase role="special">}</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// Inject ptr to our value_ member into yield_handler<>: result will</phrase>
- <phrase role="comment">// be stored here.</phrase>
- <phrase role="identifier">h</phrase><phrase role="special">.</phrase><phrase role="identifier">value_</phrase> <phrase role="special">=</phrase> <phrase role="special">&</phrase> <phrase role="identifier">value_</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// asio async method returns result of calling get()</phrase>
- <phrase role="identifier">type</phrase> <phrase role="identifier">get</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">detail</phrase><phrase role="special">::</phrase><phrase role="identifier">async_result_base</phrase><phrase role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">move</phrase><phrase role="special">(</phrase> <phrase role="identifier">value_</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">private</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">type</phrase> <phrase role="identifier">value_</phrase><phrase role="special">{};</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <para>
- this <code><phrase role="identifier">async_result</phrase><phrase role="special"><></phrase></code>
- specialization reserves a member of type <code><phrase role="identifier">T</phrase></code>
- to receive the passed data item, and sets <code><phrase role="identifier">yield_handler</phrase><phrase
- role="special"><</phrase><phrase role="identifier">T</phrase><phrase role="special">>::</phrase><phrase
- role="identifier">value_</phrase></code> to point to its own data member.
- </para>
- <para>
- <code><phrase role="identifier">async_result</phrase><phrase role="special"><</phrase><phrase
- role="identifier">yield_handler</phrase><phrase role="special"><</phrase><phrase
- role="identifier">T</phrase><phrase role="special">>></phrase></code>
- overrides <code><phrase role="identifier">get</phrase><phrase role="special">()</phrase></code>.
- The override calls <code><phrase role="identifier">async_result_base</phrase><phrase
- role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special">()</phrase></code>,
- so the calling fiber suspends as described above.
- </para>
- <para>
- <code><phrase role="identifier">yield_handler</phrase><phrase role="special"><</phrase><phrase
- role="identifier">T</phrase><phrase role="special">>::</phrase><phrase
- role="keyword">operator</phrase><phrase role="special">()(</phrase><phrase
- role="identifier">error_code</phrase><phrase role="special">,</phrase> <phrase
- role="identifier">T</phrase><phrase role="special">)</phrase></code> stores
- its passed <code><phrase role="identifier">T</phrase></code> value into
- <code><phrase role="identifier">async_result</phrase><phrase role="special"><</phrase><phrase
- role="identifier">yield_handler</phrase><phrase role="special"><</phrase><phrase
- role="identifier">T</phrase><phrase role="special">>>::</phrase><phrase
- role="identifier">value_</phrase></code>.
- </para>
- <para>
- Then it passes control to <code><phrase role="identifier">yield_handler_base</phrase><phrase
- role="special">::</phrase><phrase role="keyword">operator</phrase><phrase
- role="special">()(</phrase><phrase role="identifier">error_code</phrase><phrase
- role="special">)</phrase></code> to deal with waking the original fiber as
- described above.
- </para>
- <para>
- When <code><phrase role="identifier">async_result</phrase><phrase role="special"><</phrase><phrase
- role="identifier">yield_handler</phrase><phrase role="special"><</phrase><phrase
- role="identifier">T</phrase><phrase role="special">>>::</phrase><phrase
- role="identifier">get</phrase><phrase role="special">()</phrase></code> resumes,
- it returns the stored <code><phrase role="identifier">value_</phrase></code>
- to <code><phrase role="identifier">async_something</phrase><phrase role="special">()</phrase></code>
- and ultimately to <code><phrase role="identifier">async_something</phrase><phrase
- role="special">()</phrase></code>’s caller.
- </para>
- <para>
- The case of a callback signature <code><phrase role="keyword">void</phrase><phrase
- role="special">(</phrase><phrase role="identifier">T</phrase><phrase role="special">)</phrase></code>
- is handled by having <code><phrase role="identifier">yield_handler</phrase><phrase
- role="special"><</phrase><phrase role="identifier">T</phrase><phrase role="special">>::</phrase><phrase
- role="keyword">operator</phrase><phrase role="special">()(</phrase><phrase
- role="identifier">T</phrase><phrase role="special">)</phrase></code> engage
- the <code><phrase role="keyword">void</phrase><phrase role="special">(</phrase><phrase
- role="identifier">error_code</phrase><phrase role="special">,</phrase> <phrase
- role="identifier">T</phrase><phrase role="special">)</phrase></code> machinery,
- passing a <quote>success</quote> <code><phrase role="identifier">error_code</phrase></code>.
- </para>
- <para>
- The source code above is found in <ulink url="../../examples/asio/yield.hpp">yield.hpp</ulink>
- and <ulink url="../../examples/asio/detail/yield.hpp">detail/yield.hpp</ulink>.
- </para>
- </section>
- </section>
- <section id="fiber.nonblocking">
- <title><anchor id="nonblocking"/><link linkend="fiber.nonblocking">Integrating
- Fibers with Nonblocking I/O</link></title>
- <bridgehead renderas="sect3" id="fiber.nonblocking.h0">
- <phrase id="fiber.nonblocking.overview"/><link linkend="fiber.nonblocking.overview">Overview</link>
- </bridgehead>
- <para>
- <emphasis>Nonblocking</emphasis> I/O is distinct from <emphasis>asynchronous</emphasis>
- I/O. A true async I/O operation promises to initiate the operation and notify
- the caller on completion, usually via some sort of callback (as described in
- <link linkend="callbacks">Integrating Fibers with Asynchronous Callbacks</link>).
- </para>
- <para>
- In contrast, a nonblocking I/O operation refuses to start at all if it would
- be necessary to block, returning an error code such as <ulink url="http://man7.org/linux/man-pages/man3/errno.3.html"><code><phrase
- role="identifier">EWOULDBLOCK</phrase></code></ulink>. The operation is performed
- only when it can complete immediately. In effect, the caller must repeatedly
- retry the operation until it stops returning <code><phrase role="identifier">EWOULDBLOCK</phrase></code>.
- </para>
- <para>
- In a classic event-driven program, it can be something of a headache to use
- nonblocking I/O. At the point where the nonblocking I/O is attempted, a return
- value of <code><phrase role="identifier">EWOULDBLOCK</phrase></code> requires
- the caller to pass control back to the main event loop, arranging to retry
- again on the next iteration.
- </para>
- <para>
- Worse, a nonblocking I/O operation might <emphasis>partially</emphasis> succeed.
- That means that the relevant business logic must continue receiving control
- on every main loop iteration until all required data have been processed: a
- doubly-nested loop, implemented as a callback-driven state machine.
- </para>
- <para>
- <emphasis role="bold">Boost.Fiber</emphasis> can simplify this problem immensely.
- Once you have integrated with the application's main loop as described in
- <link linkend="integration">Sharing a Thread with Another Main Loop</link>,
- waiting for the next main-loop iteration is as simple as calling <link linkend="this_fiber_yield"><code>this_fiber::yield()</code></link>.
- </para>
- <bridgehead renderas="sect3" id="fiber.nonblocking.h1">
- <phrase id="fiber.nonblocking.example_nonblocking_api"/><link linkend="fiber.nonblocking.example_nonblocking_api">Example
- Nonblocking API</link>
- </bridgehead>
- <para>
- For purposes of illustration, consider this API:
- </para>
- <para>
- <programlisting><phrase role="keyword">class</phrase> <phrase role="identifier">NonblockingAPI</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">NonblockingAPI</phrase><phrase role="special">();</phrase>
- <phrase role="comment">// nonblocking operation: may return EWOULDBLOCK</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">read</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">&</phrase> <phrase role="identifier">data</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">desired</phrase><phrase role="special">);</phrase>
- <phrase role="special">...</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <bridgehead renderas="sect3" id="fiber.nonblocking.h2">
- <phrase id="fiber.nonblocking.polling_for_completion"/><link linkend="fiber.nonblocking.polling_for_completion">Polling
- for Completion</link>
- </bridgehead>
- <para>
- We can build a low-level wrapper around <code><phrase role="identifier">NonblockingAPI</phrase><phrase
- role="special">::</phrase><phrase role="identifier">read</phrase><phrase role="special">()</phrase></code>
- that shields its caller from ever having to deal with <code><phrase role="identifier">EWOULDBLOCK</phrase></code>:
- </para>
- <para>
- <programlisting><phrase role="comment">// guaranteed not to return EWOULDBLOCK</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">read_chunk</phrase><phrase role="special">(</phrase> <phrase role="identifier">NonblockingAPI</phrase> <phrase role="special">&</phrase> <phrase role="identifier">api</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">&</phrase> <phrase role="identifier">data</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">desired</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">error</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">EWOULDBLOCK</phrase> <phrase role="special">==</phrase> <phrase role="special">(</phrase> <phrase role="identifier">error</phrase> <phrase role="special">=</phrase> <phrase role="identifier">api</phrase><phrase role="special">.</phrase><phrase role="identifier">read</phrase><phrase role="special">(</phrase> <phrase role="identifier">data</phrase><phrase role="special">,</phrase> <phrase role="identifier">desired</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// not ready yet -- try again on the next iteration of the</phrase>
- <phrase role="comment">// application's main loop</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">yield</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">error</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <bridgehead renderas="sect3" id="fiber.nonblocking.h3">
- <phrase id="fiber.nonblocking.filling_all_desired_data"/><link linkend="fiber.nonblocking.filling_all_desired_data">Filling
- All Desired Data</link>
- </bridgehead>
- <para>
- Given <code><phrase role="identifier">read_chunk</phrase><phrase role="special">()</phrase></code>,
- we can straightforwardly iterate until we have all desired data:
- </para>
- <para>
- <programlisting><phrase role="comment">// keep reading until desired length, EOF or error</phrase>
- <phrase role="comment">// may return both partial data and nonzero error</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">read_desired</phrase><phrase role="special">(</phrase> <phrase role="identifier">NonblockingAPI</phrase> <phrase role="special">&</phrase> <phrase role="identifier">api</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">&</phrase> <phrase role="identifier">data</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">desired</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// we're going to accumulate results into 'data'</phrase>
- <phrase role="identifier">data</phrase><phrase role="special">.</phrase><phrase role="identifier">clear</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">chunk</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">error</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">data</phrase><phrase role="special">.</phrase><phrase role="identifier">length</phrase><phrase role="special">()</phrase> <phrase role="special"><</phrase> <phrase role="identifier">desired</phrase> <phrase role="special">&&</phrase>
- <phrase role="special">(</phrase> <phrase role="identifier">error</phrase> <phrase role="special">=</phrase> <phrase role="identifier">read_chunk</phrase><phrase role="special">(</phrase> <phrase role="identifier">api</phrase><phrase role="special">,</phrase> <phrase role="identifier">chunk</phrase><phrase role="special">,</phrase> <phrase role="identifier">desired</phrase> <phrase role="special">-</phrase> <phrase role="identifier">data</phrase><phrase role="special">.</phrase><phrase role="identifier">length</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">==</phrase> <phrase role="number">0</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">data</phrase><phrase role="special">.</phrase><phrase role="identifier">append</phrase><phrase role="special">(</phrase> <phrase role="identifier">chunk</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">error</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- (Of <emphasis>course</emphasis> there are more efficient ways to accumulate
- string data. That's not the point of this example.)
- </para>
- <bridgehead renderas="sect3" id="fiber.nonblocking.h4">
- <phrase id="fiber.nonblocking.wrapping_it_up"/><link linkend="fiber.nonblocking.wrapping_it_up">Wrapping
- it Up</link>
- </bridgehead>
- <para>
- Finally, we can define a relevant exception:
- </para>
- <para>
- <programlisting><phrase role="comment">// exception class augmented with both partially-read data and errorcode</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">IncompleteRead</phrase> <phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">runtime_error</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">IncompleteRead</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">what</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">partial</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">:</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">runtime_error</phrase><phrase role="special">(</phrase> <phrase role="identifier">what</phrase><phrase role="special">),</phrase>
- <phrase role="identifier">partial_</phrase><phrase role="special">(</phrase> <phrase role="identifier">partial</phrase><phrase role="special">),</phrase>
- <phrase role="identifier">ec_</phrase><phrase role="special">(</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">get_partial</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">partial_</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">get_errorcode</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">ec_</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">private</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">partial_</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">ec_</phrase><phrase role="special">;</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <para>
- and write a simple <code><phrase role="identifier">read</phrase><phrase role="special">()</phrase></code>
- function that either returns all desired data or throws <code><phrase role="identifier">IncompleteRead</phrase></code>:
- </para>
- <para>
- <programlisting><phrase role="comment">// read all desired data or throw IncompleteRead</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">read</phrase><phrase role="special">(</phrase> <phrase role="identifier">NonblockingAPI</phrase> <phrase role="special">&</phrase> <phrase role="identifier">api</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">desired</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">data</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">ec</phrase><phrase role="special">(</phrase> <phrase role="identifier">read_desired</phrase><phrase role="special">(</phrase> <phrase role="identifier">api</phrase><phrase role="special">,</phrase> <phrase role="identifier">data</phrase><phrase role="special">,</phrase> <phrase role="identifier">desired</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// for present purposes, EOF isn't a failure</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="number">0</phrase> <phrase role="special">==</phrase> <phrase role="identifier">ec</phrase> <phrase role="special">||</phrase> <phrase role="identifier">EOF</phrase> <phrase role="special">==</phrase> <phrase role="identifier">ec</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">data</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// oh oh, partial read</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ostringstream</phrase> <phrase role="identifier">msg</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">msg</phrase> <phrase role="special"><<</phrase> <phrase role="string">"NonblockingAPI::read() error "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">ec</phrase> <phrase role="special"><<</phrase> <phrase role="string">" after "</phrase>
- <phrase role="special"><<</phrase> <phrase role="identifier">data</phrase><phrase role="special">.</phrase><phrase role="identifier">length</phrase><phrase role="special">()</phrase> <phrase role="special"><<</phrase> <phrase role="string">" of "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">desired</phrase> <phrase role="special"><<</phrase> <phrase role="string">" characters"</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">throw</phrase> <phrase role="identifier">IncompleteRead</phrase><phrase role="special">(</phrase> <phrase role="identifier">msg</phrase><phrase role="special">.</phrase><phrase role="identifier">str</phrase><phrase role="special">(),</phrase> <phrase role="identifier">data</phrase><phrase role="special">,</phrase> <phrase role="identifier">ec</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- Once we can transparently wait for the next main-loop iteration using <link linkend="this_fiber_yield"><code>this_fiber::yield()</code></link>,
- ordinary encapsulation Just Works.
- </para>
- <para>
- The source code above is found in <ulink url="../../examples/adapt_nonblocking.cpp">adapt_nonblocking.cpp</ulink>.
- </para>
- </section>
- <section id="fiber.when_any">
- <title><anchor id="when_any"/><link linkend="fiber.when_any">when_any / when_all
- functionality</link></title>
- <bridgehead renderas="sect3" id="fiber.when_any.h0">
- <phrase id="fiber.when_any.overview"/><link linkend="fiber.when_any.overview">Overview</link>
- </bridgehead>
- <para>
- A bit of wisdom from the early days of computing still holds true today: prefer
- to model program state using the instruction pointer rather than with Boolean
- flags. In other words, if the program must <quote>do something</quote> and
- then do something almost the same, but with minor changes... perhaps parts
- of that something should be broken out as smaller separate functions, rather
- than introducing flags to alter the internal behavior of a monolithic function.
- </para>
- <para>
- To that we would add: prefer to describe control flow using C++ native constructs
- such as function calls, <code><phrase role="keyword">if</phrase></code>, <code><phrase
- role="keyword">while</phrase></code>, <code><phrase role="keyword">for</phrase></code>,
- <code><phrase role="keyword">do</phrase></code> et al. rather than as chains
- of callbacks.
- </para>
- <para>
- One of the great strengths of <emphasis role="bold">Boost.Fiber</emphasis>
- is the flexibility it confers on the coder to restructure an application from
- chains of callbacks to straightforward C++ statement sequence, even when code
- in that fiber is in fact interleaved with code running in other fibers.
- </para>
- <para>
- There has been much recent discussion about the benefits of when_any and when_all
- functionality. When dealing with asynchronous and possibly unreliable services,
- these are valuable idioms. But of course when_any and when_all are closely
- tied to the use of chains of callbacks.
- </para>
- <para>
- This section presents recipes for achieving the same ends, in the context of
- a fiber that wants to <quote>do something</quote> when one or more other independent
- activities have completed. Accordingly, these are <code><phrase role="identifier">wait_something</phrase><phrase
- role="special">()</phrase></code> functions rather than <code><phrase role="identifier">when_something</phrase><phrase
- role="special">()</phrase></code> functions. The expectation is that the calling
- fiber asks to launch those independent activities, then waits for them, then
- sequentially proceeds with whatever processing depends on those results.
- </para>
- <para>
- The function names shown (e.g. <link linkend="wait_first_simple"><code><phrase
- role="identifier">wait_first_simple</phrase><phrase role="special">()</phrase></code></link>)
- are for illustrative purposes only, because all these functions have been bundled
- into a single source file. Presumably, if (say) <link linkend="wait_first_success"><code><phrase
- role="identifier">wait_first_success</phrase><phrase role="special">()</phrase></code></link>
- best suits your application needs, you could introduce that variant with the
- name <code><phrase role="identifier">wait_any</phrase><phrase role="special">()</phrase></code>.
- </para>
- <note>
- <para>
- The functions presented in this section accept variadic argument lists of
- task functions. Corresponding <code><phrase role="identifier">wait_something</phrase><phrase
- role="special">()</phrase></code> functions accepting a container of task
- functions are left as an exercise for the interested reader. Those should
- actually be simpler. Most of the complexity would arise from overloading
- the same name for both purposes.
- </para>
- </note>
- <para>
- All the source code for this section is found in <ulink url="../../examples/wait_stuff.cpp">wait_stuff.cpp</ulink>.
- </para>
- <bridgehead renderas="sect3" id="fiber.when_any.h1">
- <phrase id="fiber.when_any.example_task_function"/><link linkend="fiber.when_any.example_task_function">Example
- Task Function</link>
- </bridgehead>
- <para>
- <anchor id="wait_sleeper"/>We found it convenient to model an asynchronous
- task using this function:
- </para>
- <para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">T</phrase> <phrase role="identifier">sleeper_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">T</phrase> <phrase role="identifier">item</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">ms</phrase><phrase role="special">,</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">thrw</phrase> <phrase role="special">=</phrase> <phrase role="keyword">false</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ostringstream</phrase> <phrase role="identifier">descb</phrase><phrase role="special">,</phrase> <phrase role="identifier">funcb</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">descb</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">item</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">desc</phrase><phrase role="special">(</phrase> <phrase role="identifier">descb</phrase><phrase role="special">.</phrase><phrase role="identifier">str</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">funcb</phrase> <phrase role="special"><<</phrase> <phrase role="string">" sleeper("</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">item</phrase> <phrase role="special"><<</phrase> <phrase role="string">")"</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">Verbose</phrase> <phrase role="identifier">v</phrase><phrase role="special">(</phrase> <phrase role="identifier">funcb</phrase><phrase role="special">.</phrase><phrase role="identifier">str</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">sleep_for</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">milliseconds</phrase><phrase role="special">(</phrase> <phrase role="identifier">ms</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">thrw</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">throw</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">runtime_error</phrase><phrase role="special">(</phrase> <phrase role="identifier">desc</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">item</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- with type-specific <code><phrase role="identifier">sleeper</phrase><phrase
- role="special">()</phrase></code> <quote>front ends</quote> for <code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase></code>,
- <code><phrase role="keyword">double</phrase></code> and <code><phrase role="keyword">int</phrase></code>.
- </para>
- <para>
- <code><phrase role="identifier">Verbose</phrase></code> simply prints a message
- to <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">cout</phrase></code> on construction and destruction.
- </para>
- <para>
- Basically:
- </para>
- <orderedlist>
- <listitem>
- <simpara>
- <code><phrase role="identifier">sleeper</phrase><phrase role="special">()</phrase></code>
- prints a start message;
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- sleeps for the specified number of milliseconds;
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- if <code><phrase role="identifier">thrw</phrase></code> is passed as <code><phrase
- role="keyword">true</phrase></code>, throws a string description of the
- passed <code><phrase role="identifier">item</phrase></code>;
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- else returns the passed <code><phrase role="identifier">item</phrase></code>.
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- On the way out, <code><phrase role="identifier">sleeper</phrase><phrase
- role="special">()</phrase></code> produces a stop message.
- </simpara>
- </listitem>
- </orderedlist>
- <para>
- This function will feature in the example calls to the various functions presented
- below.
- </para>
- <section id="fiber.when_any.when_any">
- <title><link linkend="fiber.when_any.when_any">when_any</link></title>
- <section id="fiber.when_any.when_any.when_any__simple_completion">
- <title><anchor id="wait_first_simple_section"/><link linkend="fiber.when_any.when_any.when_any__simple_completion">when_any,
- simple completion</link></title>
- <para>
- The simplest case is when you only need to know that the first of a set
- of asynchronous tasks has completed — but you don't need to obtain a return
- value, and you're confident that they will not throw exceptions.
- </para>
- <para>
- <anchor id="wait_done"/>For this we introduce a <code><phrase role="identifier">Done</phrase></code>
- class to wrap a <code><phrase role="keyword">bool</phrase></code> variable
- with a <link linkend="class_condition_variable"><code>condition_variable</code></link> and a <link linkend="class_mutex"><code>mutex</code></link>:
- </para>
- <para>
- <programlisting><phrase role="comment">// Wrap canonical pattern for condition_variable + bool flag</phrase>
- <phrase role="keyword">struct</phrase> <phrase role="identifier">Done</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">private</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">condition_variable</phrase> <phrase role="identifier">cond</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="identifier">mutex</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">ready</phrase> <phrase role="special">=</phrase> <phrase role="keyword">false</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special"><</phrase> <phrase role="identifier">Done</phrase> <phrase role="special">></phrase> <phrase role="identifier">ptr</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">></phrase> <phrase role="identifier">lock</phrase><phrase role="special">(</phrase> <phrase role="identifier">mutex</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">cond</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">(</phrase> <phrase role="identifier">lock</phrase><phrase role="special">,</phrase> <phrase role="special">[</phrase><phrase role="keyword">this</phrase><phrase role="special">](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">ready</phrase><phrase role="special">;</phrase> <phrase role="special">});</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
- <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">></phrase> <phrase role="identifier">lock</phrase><phrase role="special">(</phrase> <phrase role="identifier">mutex</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">ready</phrase> <phrase role="special">=</phrase> <phrase role="keyword">true</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase> <phrase role="comment">// release mutex</phrase>
- <phrase role="identifier">cond</phrase><phrase role="special">.</phrase><phrase role="identifier">notify_one</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <para>
- The pattern we follow throughout this section is to pass a <ulink url="http://www.cplusplus.com/reference/memory/shared_ptr/"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">shared_ptr</phrase><phrase role="special"><></phrase></code></ulink>
- to the relevant synchronization object to the various tasks' fiber functions.
- This eliminates nagging questions about the lifespan of the synchronization
- object relative to the last of the fibers.
- </para>
- <para>
- <anchor id="wait_first_simple"/><code><phrase role="identifier">wait_first_simple</phrase><phrase
- role="special">()</phrase></code> uses that tactic for <link linkend="wait_done"><code><phrase
- role="identifier">Done</phrase></code></link>:
- </para>
- <para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait_first_simple</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// Use shared_ptr because each function's fiber will bind it separately,</phrase>
- <phrase role="comment">// and we're going to return before the last of them completes.</phrase>
- <phrase role="keyword">auto</phrase> <phrase role="identifier">done</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special"><</phrase> <phrase role="identifier">Done</phrase> <phrase role="special">>()</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">wait_first_simple_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">done</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">done</phrase><phrase role="special">-></phrase><phrase role="identifier">wait</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- <anchor id="wait_first_simple_impl"/><code><phrase role="identifier">wait_first_simple_impl</phrase><phrase
- role="special">()</phrase></code> is an ordinary recursion over the argument
- pack, capturing <code><phrase role="identifier">Done</phrase><phrase role="special">::</phrase><phrase
- role="identifier">ptr</phrase></code> for each new fiber:
- </para>
- <para>
- <programlisting><phrase role="comment">// Degenerate case: when there are no functions to wait for, return</phrase>
- <phrase role="comment">// immediately.</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait_first_simple_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">Done</phrase><phrase role="special">::</phrase><phrase role="identifier">ptr</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// When there's at least one function to wait for, launch it and recur to</phrase>
- <phrase role="comment">// process the rest.</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait_first_simple_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">Done</phrase><phrase role="special">::</phrase><phrase role="identifier">ptr</phrase> <phrase role="identifier">done</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="special">[</phrase><phrase role="identifier">done</phrase><phrase role="special">,</phrase> <phrase role="identifier">function</phrase><phrase role="special">](){</phrase>
- <phrase role="identifier">function</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">done</phrase><phrase role="special">-></phrase><phrase role="identifier">notify</phrase><phrase role="special">();</phrase>
- <phrase role="special">}).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">wait_first_simple_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">done</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- The body of the fiber's lambda is extremely simple, as promised: call the
- function, notify <link linkend="wait_done"><code><phrase role="identifier">Done</phrase></code></link>
- when it returns. The first fiber to do so allows <code><phrase role="identifier">wait_first_simple</phrase><phrase
- role="special">()</phrase></code> to return — which is why it's useful to
- have <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">shared_ptr</phrase><phrase role="special"><</phrase><phrase
- role="identifier">Done</phrase><phrase role="special">></phrase></code>
- manage the lifespan of our <code><phrase role="identifier">Done</phrase></code>
- object rather than declaring it as a stack variable in <code><phrase role="identifier">wait_first_simple</phrase><phrase
- role="special">()</phrase></code>.
- </para>
- <para>
- This is how you might call it:
- </para>
- <para>
- <programlisting><phrase role="identifier">wait_first_simple</phrase><phrase role="special">(</phrase>
- <phrase role="special">[](){</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wfs_long"</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wfs_medium"</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wfs_short"</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
- </programlisting>
- </para>
- <para>
- In this example, control resumes after <code><phrase role="identifier">wait_first_simple</phrase><phrase
- role="special">()</phrase></code> when <link linkend="wait_sleeper"><code><phrase
- role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase
- role="string">"wfs_short"</phrase><phrase role="special">,</phrase>
- <phrase role="number">50</phrase><phrase role="special">)</phrase></code></link>
- completes — even though the other two <code><phrase role="identifier">sleeper</phrase><phrase
- role="special">()</phrase></code> fibers are still running.
- </para>
- </section>
- <section id="fiber.when_any.when_any.when_any__return_value">
- <title><link linkend="fiber.when_any.when_any.when_any__return_value">when_any,
- return value</link></title>
- <para>
- It seems more useful to add the ability to capture the return value from
- the first of the task functions to complete. Again, we assume that none
- will throw an exception.
- </para>
- <para>
- One tactic would be to adapt our <link linkend="wait_done"><code><phrase
- role="identifier">Done</phrase></code></link> class to store the first
- of the return values, rather than a simple <code><phrase role="keyword">bool</phrase></code>.
- However, we choose instead to use a <link linkend="class_buffered_channel"><code>buffered_channel<></code></link>.
- We'll only need to enqueue the first value, so we'll <link linkend="buffered_channel_close"><code>buffered_channel::close()</code></link> it
- once we've retrieved that value. Subsequent <code><phrase role="identifier">push</phrase><phrase
- role="special">()</phrase></code> calls will return <code><phrase role="identifier">closed</phrase></code>.
- </para>
- <para>
- <anchor id="wait_first_value"/>
- <programlisting><phrase role="comment">// Assume that all passed functions have the same return type. The return type</phrase>
- <phrase role="comment">// of wait_first_value() is the return type of the first passed function. It is</phrase>
- <phrase role="comment">// simply invalid to pass NO functions.</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase>
- <phrase role="identifier">wait_first_value</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="identifier">return_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">auto</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special"><</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">>(</phrase> <phrase role="number">64</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// launch all the relevant fibers</phrase>
- <phrase role="identifier">wait_first_value_impl</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">function</phrase><phrase role="special">),</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// retrieve the first value</phrase>
- <phrase role="identifier">return_t</phrase> <phrase role="identifier">value</phrase><phrase role="special">(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">-></phrase><phrase role="identifier">value_pop</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// close the channel: no subsequent push() has to succeed</phrase>
- <phrase role="identifier">chanp</phrase><phrase role="special">-></phrase><phrase role="identifier">close</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">value</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- <anchor id="wait_first_value_impl"/>The meat of the <code><phrase role="identifier">wait_first_value_impl</phrase><phrase
- role="special">()</phrase></code> function is as you might expect:
- </para>
- <para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait_first_value_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">></phrase> <phrase role="identifier">chan</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="special">[</phrase><phrase role="identifier">chan</phrase><phrase role="special">,</phrase> <phrase role="identifier">function</phrase><phrase role="special">](){</phrase>
- <phrase role="comment">// Ignore channel_op_status returned by push():</phrase>
- <phrase role="comment">// might be closed; we simply don't care.</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">-></phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">function</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="special">}).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- It calls the passed function, pushes its return value and ignores the
- <code><phrase role="identifier">push</phrase><phrase role="special">()</phrase></code>
- result. You might call it like this:
- </para>
- <para>
- <programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">result</phrase> <phrase role="special">=</phrase> <phrase role="identifier">wait_first_value</phrase><phrase role="special">(</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wfv_third"</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wfv_second"</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wfv_first"</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"wait_first_value() => "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">result</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">result</phrase> <phrase role="special">==</phrase> <phrase role="string">"wfv_first"</phrase><phrase role="special">);</phrase>
- </programlisting>
- </para>
- </section>
- <section id="fiber.when_any.when_any.when_any__produce_first_outcome__whether_result_or_exception">
- <title><link linkend="fiber.when_any.when_any.when_any__produce_first_outcome__whether_result_or_exception">when_any,
- produce first outcome, whether result or exception</link></title>
- <para>
- We may not be running in an environment in which we can guarantee no exception
- will be thrown by any of our task functions. In that case, the above implementations
- of <code><phrase role="identifier">wait_first_something</phrase><phrase
- role="special">()</phrase></code> would be naïve: as mentioned in <link
- linkend="exceptions">the section on Fiber Management</link>, an uncaught
- exception in one of our task fibers would cause <code><phrase role="identifier">std</phrase><phrase
- role="special">::</phrase><phrase role="identifier">terminate</phrase><phrase
- role="special">()</phrase></code> to be called.
- </para>
- <para>
- Let's at least ensure that such an exception would propagate to the fiber
- awaiting the first result. We can use <link linkend="class_future"><code>future<></code></link> to transport
- either a return value or an exception. Therefore, we will change <link
- linkend="wait_first_value"><code><phrase role="identifier">wait_first_value</phrase><phrase
- role="special">()</phrase></code></link>'s <link linkend="class_buffered_channel"><code>buffered_channel<></code></link> to
- hold <code><phrase role="identifier">future</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">T</phrase> <phrase role="special">></phrase></code>
- items instead of simply <code><phrase role="identifier">T</phrase></code>.
- </para>
- <para>
- Once we have a <code><phrase role="identifier">future</phrase><phrase role="special"><></phrase></code>
- in hand, all we need do is call <link linkend="future_get"><code>future::get()</code></link>, which will either
- return the value or rethrow the exception.
- </para>
- <para>
- <anchor id="wait_first_outcome"/>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase>
- <phrase role="identifier">wait_first_outcome</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// In this case, the value we pass through the channel is actually a</phrase>
- <phrase role="comment">// future -- which is already ready. future can carry either a value or an</phrase>
- <phrase role="comment">// exception.</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="identifier">return_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">future_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">auto</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">(</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special"><</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">>(</phrase> <phrase role="number">64</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// launch all the relevant fibers</phrase>
- <phrase role="identifier">wait_first_outcome_impl</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">function</phrase><phrase role="special">),</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// retrieve the first future</phrase>
- <phrase role="identifier">future_t</phrase> <phrase role="identifier">future</phrase><phrase role="special">(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">-></phrase><phrase role="identifier">value_pop</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// close the channel: no subsequent push() has to succeed</phrase>
- <phrase role="identifier">chanp</phrase><phrase role="special">-></phrase><phrase role="identifier">close</phrase><phrase role="special">();</phrase>
- <phrase role="comment">// either return value or throw exception</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- So far so good — but there's a timing issue. How should we obtain the <code><phrase
- role="identifier">future</phrase><phrase role="special"><></phrase></code>
- to <link linkend="buffered_channel_push"><code>buffered_channel::push()</code></link> on the queue?
- </para>
- <para>
- We could call <link linkend="fibers_async"><code>fibers::async()</code></link>. That would certainly produce
- a <code><phrase role="identifier">future</phrase><phrase role="special"><></phrase></code>
- for the task function. The trouble is that it would return too quickly!
- We only want <code><phrase role="identifier">future</phrase><phrase role="special"><></phrase></code>
- items for <emphasis>completed</emphasis> tasks on our <code><phrase role="identifier">queue</phrase><phrase
- role="special"><></phrase></code>. In fact, we only want the <code><phrase
- role="identifier">future</phrase><phrase role="special"><></phrase></code>
- for the one that completes first. If each fiber launched by <code><phrase
- role="identifier">wait_first_outcome</phrase><phrase role="special">()</phrase></code>
- were to <code><phrase role="identifier">push</phrase><phrase role="special">()</phrase></code>
- the result of calling <code><phrase role="identifier">async</phrase><phrase
- role="special">()</phrase></code>, the queue would only ever report the
- result of the leftmost task item — <emphasis>not</emphasis> the one that
- completes most quickly.
- </para>
- <para>
- Calling <link linkend="future_get"><code>future::get()</code></link> on the future returned by <code><phrase
- role="identifier">async</phrase><phrase role="special">()</phrase></code>
- wouldn't be right. You can only call <code><phrase role="identifier">get</phrase><phrase
- role="special">()</phrase></code> once per <code><phrase role="identifier">future</phrase><phrase
- role="special"><></phrase></code> instance! And if there were an
- exception, it would be rethrown inside the helper fiber at the producer
- end of the queue, rather than propagated to the consumer end.
- </para>
- <para>
- We could call <link linkend="future_wait"><code>future::wait()</code></link>. That would block the helper fiber
- until the <code><phrase role="identifier">future</phrase><phrase role="special"><></phrase></code>
- became ready, at which point we could <code><phrase role="identifier">push</phrase><phrase
- role="special">()</phrase></code> it to be retrieved by <code><phrase role="identifier">wait_first_outcome</phrase><phrase
- role="special">()</phrase></code>.
- </para>
- <para>
- That would work — but there's a simpler tactic that avoids creating an extra
- fiber. We can wrap the task function in a <link linkend="class_packaged_task"><code>packaged_task<></code></link>.
- While one naturally thinks of passing a <code><phrase role="identifier">packaged_task</phrase><phrase
- role="special"><></phrase></code> to a new fiber — that is, in fact,
- what <code><phrase role="identifier">async</phrase><phrase role="special">()</phrase></code>
- does — in this case, we're already running in the helper fiber at the producer
- end of the queue! We can simply <emphasis>call</emphasis> the <code><phrase
- role="identifier">packaged_task</phrase><phrase role="special"><></phrase></code>.
- On return from that call, the task function has completed, meaning that
- the <code><phrase role="identifier">future</phrase><phrase role="special"><></phrase></code>
- obtained from the <code><phrase role="identifier">packaged_task</phrase><phrase
- role="special"><></phrase></code> is certain to be ready. At that
- point we can simply <code><phrase role="identifier">push</phrase><phrase
- role="special">()</phrase></code> it to the queue.
- </para>
- <para>
- <anchor id="wait_first_outcome_impl"/>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">CHANP</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait_first_outcome_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">CHANP</phrase> <phrase role="identifier">chan</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase>
- <phrase role="comment">// Use std::bind() here for C++11 compatibility. C++11 lambda capture</phrase>
- <phrase role="comment">// can't move a move-only Fn type, but bind() can. Let bind() move the</phrase>
- <phrase role="comment">// channel pointer and the function into the bound object, passing</phrase>
- <phrase role="comment">// references into the lambda.</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">bind</phrase><phrase role="special">(</phrase>
- <phrase role="special">[](</phrase> <phrase role="identifier">CHANP</phrase> <phrase role="special">&</phrase> <phrase role="identifier">chan</phrase><phrase role="special">,</phrase>
- <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="special">&</phrase> <phrase role="identifier">function</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// Instantiate a packaged_task to capture any exception thrown by</phrase>
- <phrase role="comment">// function.</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">packaged_task</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase><phrase role="special">()</phrase> <phrase role="special">></phrase> <phrase role="identifier">task</phrase><phrase role="special">(</phrase> <phrase role="identifier">function</phrase><phrase role="special">);</phrase>
- <phrase role="comment">// Immediately run this packaged_task on same fiber. We want</phrase>
- <phrase role="comment">// function() to have completed BEFORE we push the future.</phrase>
- <phrase role="identifier">task</phrase><phrase role="special">();</phrase>
- <phrase role="comment">// Pass the corresponding future to consumer. Ignore</phrase>
- <phrase role="comment">// channel_op_status returned by push(): might be closed; we</phrase>
- <phrase role="comment">// simply don't care.</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">-></phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase> <phrase role="identifier">task</phrase><phrase role="special">.</phrase><phrase role="identifier">get_future</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="special">},</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">function</phrase><phrase role="special">)</phrase>
- <phrase role="special">)).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- Calling it might look like this:
- </para>
- <para>
- <programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">result</phrase> <phrase role="special">=</phrase> <phrase role="identifier">wait_first_outcome</phrase><phrase role="special">(</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wfos_first"</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wfos_second"</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wfos_third"</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"wait_first_outcome(success) => "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">result</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">result</phrase> <phrase role="special">==</phrase> <phrase role="string">"wfos_first"</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">thrown</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">try</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">result</phrase> <phrase role="special">=</phrase> <phrase role="identifier">wait_first_outcome</phrase><phrase role="special">(</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wfof_first"</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">,</phrase> <phrase role="keyword">true</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wfof_second"</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wfof_third"</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
- <phrase role="special">}</phrase> <phrase role="keyword">catch</phrase> <phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">e</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">thrown</phrase> <phrase role="special">=</phrase> <phrase role="identifier">e</phrase><phrase role="special">.</phrase><phrase role="identifier">what</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"wait_first_outcome(fail) threw '"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">thrown</phrase>
- <phrase role="special"><<</phrase> <phrase role="string">"'"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">thrown</phrase> <phrase role="special">==</phrase> <phrase role="string">"wfof_first"</phrase><phrase role="special">);</phrase>
- </programlisting>
- </para>
- </section>
- <section id="fiber.when_any.when_any.when_any__produce_first_success">
- <title><link linkend="fiber.when_any.when_any.when_any__produce_first_success">when_any,
- produce first success</link></title>
- <para>
- One scenario for <quote>when_any</quote> functionality is when we're redundantly
- contacting some number of possibly-unreliable web services. Not only might
- they be slow — any one of them might produce a failure rather than the desired
- result.
- </para>
- <para>
- In such a case, <link linkend="wait_first_outcome"><code><phrase role="identifier">wait_first_outcome</phrase><phrase
- role="special">()</phrase></code></link> isn't the right approach. If one
- of the services produces an error quickly, while another follows up with
- a real answer, we don't want to prefer the error just because it arrived
- first!
- </para>
- <para>
- Given the <code><phrase role="identifier">queue</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">future</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">T</phrase> <phrase role="special">></phrase>
- <phrase role="special">></phrase></code> we already constructed for
- <code><phrase role="identifier">wait_first_outcome</phrase><phrase role="special">()</phrase></code>,
- though, we can readily recast the interface function to deliver the first
- <emphasis>successful</emphasis> result.
- </para>
- <para>
- That does beg the question: what if <emphasis>all</emphasis> the task functions
- throw an exception? In that case we'd probably better know about it.
- </para>
- <para>
- <anchor id="exception_list"/>The <ulink url="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4407.html#parallel.exceptions.synopsis">C++
- Parallelism Draft Technical Specification</ulink> proposes a <code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">exception_list</phrase></code> exception capable of delivering
- a collection of <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">exception_ptr</phrase></code>s. Until that becomes universally
- available, let's fake up an <code><phrase role="identifier">exception_list</phrase></code>
- of our own:
- </para>
- <para>
- <programlisting><phrase role="keyword">class</phrase> <phrase role="identifier">exception_list</phrase> <phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">runtime_error</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">exception_list</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">what</phrase><phrase role="special">)</phrase> <phrase role="special">:</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">runtime_error</phrase><phrase role="special">(</phrase> <phrase role="identifier">what</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase> <phrase role="special">></phrase> <phrase role="identifier">bundle_t</phrase><phrase role="special">;</phrase>
- <phrase role="comment">// N4407 proposed std::exception_list API</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">bundle_t</phrase><phrase role="special">::</phrase><phrase role="identifier">const_iterator</phrase> <phrase role="identifier">iterator</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">size</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">bundle_</phrase><phrase role="special">.</phrase><phrase role="identifier">size</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">iterator</phrase> <phrase role="identifier">begin</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">bundle_</phrase><phrase role="special">.</phrase><phrase role="identifier">begin</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">iterator</phrase> <phrase role="identifier">end</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">bundle_</phrase><phrase role="special">.</phrase><phrase role="identifier">end</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// extension to populate</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">add</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase> <phrase role="identifier">ep</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">bundle_</phrase><phrase role="special">.</phrase><phrase role="identifier">push_back</phrase><phrase role="special">(</phrase> <phrase role="identifier">ep</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">private</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">bundle_t</phrase> <phrase role="identifier">bundle_</phrase><phrase role="special">;</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <para>
- Now we can build <code><phrase role="identifier">wait_first_success</phrase><phrase
- role="special">()</phrase></code>, using <link linkend="wait_first_outcome_impl"><code><phrase
- role="identifier">wait_first_outcome_impl</phrase><phrase role="special">()</phrase></code></link>.
- </para>
- <para>
- Instead of retrieving only the first <code><phrase role="identifier">future</phrase><phrase
- role="special"><></phrase></code> from the queue, we must now loop
- over <code><phrase role="identifier">future</phrase><phrase role="special"><></phrase></code>
- items. Of course we must limit that iteration! If we launch only <code><phrase
- role="identifier">count</phrase></code> producer fibers, the <code><phrase
- role="special">(</phrase><phrase role="identifier">count</phrase><phrase
- role="special">+</phrase><phrase role="number">1</phrase><phrase role="special">)</phrase></code><superscript>st</superscript>
- <link linkend="buffered_channel_pop"><code>buffered_channel::pop()</code></link> call
- would block forever.
- </para>
- <para>
- Given a ready <code><phrase role="identifier">future</phrase><phrase role="special"><></phrase></code>,
- we can distinguish failure by calling <link linkend="future_get_exception_ptr"><code>future::get_exception_ptr()</code></link>.
- If the <code><phrase role="identifier">future</phrase><phrase role="special"><></phrase></code>
- in fact contains a result rather than an exception, <code><phrase role="identifier">get_exception_ptr</phrase><phrase
- role="special">()</phrase></code> returns <code><phrase role="keyword">nullptr</phrase></code>.
- In that case, we can confidently call <link linkend="future_get"><code>future::get()</code></link> to return
- that result to our caller.
- </para>
- <para>
- If the <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">exception_ptr</phrase></code> is <emphasis>not</emphasis>
- <code><phrase role="keyword">nullptr</phrase></code>, though, we collect
- it into our pending <code><phrase role="identifier">exception_list</phrase></code>
- and loop back for the next <code><phrase role="identifier">future</phrase><phrase
- role="special"><></phrase></code> from the queue.
- </para>
- <para>
- If we fall out of the loop — if every single task fiber threw an exception
- — we throw the <code><phrase role="identifier">exception_list</phrase></code>
- exception into which we've been collecting those <code><phrase role="identifier">std</phrase><phrase
- role="special">::</phrase><phrase role="identifier">exception_ptr</phrase></code>s.
- </para>
- <para>
- <anchor id="wait_first_success"/>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase>
- <phrase role="identifier">wait_first_success</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">count</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase> <phrase role="special">+</phrase> <phrase role="keyword">sizeof</phrase> <phrase role="special">...</phrase> <phrase role="special">(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// In this case, the value we pass through the channel is actually a</phrase>
- <phrase role="comment">// future -- which is already ready. future can carry either a value or an</phrase>
- <phrase role="comment">// exception.</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="identifier">return_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">future_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">auto</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special"><</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">>(</phrase> <phrase role="number">64</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// launch all the relevant fibers</phrase>
- <phrase role="identifier">wait_first_outcome_impl</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">function</phrase><phrase role="special">),</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// instantiate exception_list, just in case</phrase>
- <phrase role="identifier">exception_list</phrase> <phrase role="identifier">exceptions</phrase><phrase role="special">(</phrase><phrase role="string">"wait_first_success() produced only errors"</phrase><phrase role="special">);</phrase>
- <phrase role="comment">// retrieve up to 'count' results -- but stop there!</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special"><</phrase> <phrase role="identifier">count</phrase><phrase role="special">;</phrase> <phrase role="special">++</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// retrieve the next future</phrase>
- <phrase role="identifier">future_t</phrase> <phrase role="identifier">future</phrase><phrase role="special">(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">-></phrase><phrase role="identifier">value_pop</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// retrieve exception_ptr if any</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase> <phrase role="identifier">error</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get_exception_ptr</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// if no error, then yay, return value</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">error</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// close the channel: no subsequent push() has to succeed</phrase>
- <phrase role="identifier">chanp</phrase><phrase role="special">-></phrase><phrase role="identifier">close</phrase><phrase role="special">();</phrase>
- <phrase role="comment">// show caller the value we got</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// error is non-null: collect</phrase>
- <phrase role="identifier">exceptions</phrase><phrase role="special">.</phrase><phrase role="identifier">add</phrase><phrase role="special">(</phrase> <phrase role="identifier">error</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// We only arrive here when every passed function threw an exception.</phrase>
- <phrase role="comment">// Throw our collection to inform caller.</phrase>
- <phrase role="keyword">throw</phrase> <phrase role="identifier">exceptions</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- A call might look like this:
- </para>
- <para>
- <programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">result</phrase> <phrase role="special">=</phrase> <phrase role="identifier">wait_first_success</phrase><phrase role="special">(</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wfss_first"</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">,</phrase> <phrase role="keyword">true</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wfss_second"</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wfss_third"</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"wait_first_success(success) => "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">result</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">result</phrase> <phrase role="special">==</phrase> <phrase role="string">"wfss_second"</phrase><phrase role="special">);</phrase>
- </programlisting>
- </para>
- </section>
- <section id="fiber.when_any.when_any.when_any__heterogeneous_types">
- <title><link linkend="fiber.when_any.when_any.when_any__heterogeneous_types">when_any,
- heterogeneous types</link></title>
- <para>
- We would be remiss to ignore the case in which the various task functions
- have distinct return types. That means that the value returned by the first
- of them might have any one of those types. We can express that with <ulink
- url="http://www.boost.org/doc/libs/release/doc/html/variant.html">Boost.Variant</ulink>.
- </para>
- <para>
- To keep the example simple, we'll revert to pretending that none of them
- can throw an exception. That makes <code><phrase role="identifier">wait_first_value_het</phrase><phrase
- role="special">()</phrase></code> strongly resemble <link linkend="wait_first_value"><code><phrase
- role="identifier">wait_first_value</phrase><phrase role="special">()</phrase></code></link>.
- We can actually reuse <link linkend="wait_first_value_impl"><code><phrase
- role="identifier">wait_first_value_impl</phrase><phrase role="special">()</phrase></code></link>,
- merely passing <code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">variant</phrase><phrase role="special"><</phrase><phrase
- role="identifier">T0</phrase><phrase role="special">,</phrase> <phrase
- role="identifier">T1</phrase><phrase role="special">,</phrase> <phrase
- role="special">...></phrase></code> as the queue's value type rather
- than the common <code><phrase role="identifier">T</phrase></code>!
- </para>
- <para>
- Naturally this could be extended to use <link linkend="wait_first_success"><code><phrase
- role="identifier">wait_first_success</phrase><phrase role="special">()</phrase></code></link>
- semantics instead.
- </para>
- <para>
- <programlisting><phrase role="comment">// No need to break out the first Fn for interface function: let the compiler</phrase>
- <phrase role="comment">// complain if empty.</phrase>
- <phrase role="comment">// Our functions have different return types, and we might have to return any</phrase>
- <phrase role="comment">// of them. Use a variant, expanding std::result_of<Fn()>::type for each Fn in</phrase>
- <phrase role="comment">// parameter pack.</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variant</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fns</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="special">...</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">wait_first_value_het</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// Use buffered_channel<boost::variant<T1, T2, ...>>; see remarks above.</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variant</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fns</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="special">...</phrase> <phrase role="special">></phrase> <phrase role="identifier">return_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">auto</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special"><</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">>(</phrase> <phrase role="number">64</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// launch all the relevant fibers</phrase>
- <phrase role="identifier">wait_first_value_impl</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// retrieve the first value</phrase>
- <phrase role="identifier">return_t</phrase> <phrase role="identifier">value</phrase><phrase role="special">(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">-></phrase><phrase role="identifier">value_pop</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// close the channel: no subsequent push() has to succeed</phrase>
- <phrase role="identifier">chanp</phrase><phrase role="special">-></phrase><phrase role="identifier">close</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">value</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- It might be called like this:
- </para>
- <para>
- <programlisting><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">variant</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase><phrase role="special">,</phrase> <phrase role="keyword">double</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="special">></phrase> <phrase role="identifier">result</phrase> <phrase role="special">=</phrase>
- <phrase role="identifier">wait_first_value_het</phrase><phrase role="special">(</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wfvh_third"</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="number">3.14</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="number">17</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"wait_first_value_het() => "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">result</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">assert</phrase><phrase role="special">(</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special"><</phrase> <phrase role="keyword">int</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">result</phrase><phrase role="special">)</phrase> <phrase role="special">==</phrase> <phrase role="number">17</phrase><phrase role="special">);</phrase>
- </programlisting>
- </para>
- </section>
- <section id="fiber.when_any.when_any.when_any__a_dubious_alternative">
- <title><link linkend="fiber.when_any.when_any.when_any__a_dubious_alternative">when_any,
- a dubious alternative</link></title>
- <para>
- Certain topics in C++ can arouse strong passions, and exceptions are no
- exception. We cannot resist mentioning — for purely informational purposes
- — that when you need only the <emphasis>first</emphasis> result from some
- number of concurrently-running fibers, it would be possible to pass a
- <literal>shared_ptr<<link linkend="class_promise"><code>promise<></code></link>></literal> to the
- participating fibers, then cause the initiating fiber to call <link linkend="future_get"><code>future::get()</code></link> on
- its <link linkend="class_future"><code>future<></code></link>. The first fiber to call <link linkend="promise_set_value"><code>promise::set_value()</code></link> on
- that shared <code><phrase role="identifier">promise</phrase></code> will
- succeed; subsequent <code><phrase role="identifier">set_value</phrase><phrase
- role="special">()</phrase></code> calls on the same <code><phrase role="identifier">promise</phrase></code>
- instance will throw <code><phrase role="identifier">future_error</phrase></code>.
- </para>
- <para>
- Use this information at your own discretion. Beware the dark side.
- </para>
- </section>
- </section>
- <section id="fiber.when_any.when_all_functionality">
- <title><link linkend="fiber.when_any.when_all_functionality">when_all functionality</link></title>
- <section id="fiber.when_any.when_all_functionality.when_all__simple_completion">
- <title><link linkend="fiber.when_any.when_all_functionality.when_all__simple_completion">when_all,
- simple completion</link></title>
- <para>
- For the case in which we must wait for <emphasis>all</emphasis> task functions
- to complete — but we don't need results (or expect exceptions) from any of
- them — we can write <code><phrase role="identifier">wait_all_simple</phrase><phrase
- role="special">()</phrase></code> that looks remarkably like <link linkend="wait_first_simple"><code><phrase
- role="identifier">wait_first_simple</phrase><phrase role="special">()</phrase></code></link>.
- The difference is that instead of our <link linkend="wait_done"><code><phrase
- role="identifier">Done</phrase></code></link> class, we instantiate a <link linkend="class_barrier"><code>barrier</code></link> and
- call its <link linkend="barrier_wait"><code>barrier::wait()</code></link>.
- </para>
- <para>
- We initialize the <code><phrase role="identifier">barrier</phrase></code>
- with <code><phrase role="special">(</phrase><phrase role="identifier">count</phrase><phrase
- role="special">+</phrase><phrase role="number">1</phrase><phrase role="special">)</phrase></code>
- because we are launching <code><phrase role="identifier">count</phrase></code>
- fibers, plus the <code><phrase role="identifier">wait</phrase><phrase role="special">()</phrase></code>
- call within <code><phrase role="identifier">wait_all_simple</phrase><phrase
- role="special">()</phrase></code> itself.
- </para>
- <para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait_all_simple</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">count</phrase><phrase role="special">(</phrase> <phrase role="keyword">sizeof</phrase> <phrase role="special">...</phrase> <phrase role="special">(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// Initialize a barrier(count+1) because we'll immediately wait on it. We</phrase>
- <phrase role="comment">// don't want to wake up until 'count' more fibers wait on it. Even though</phrase>
- <phrase role="comment">// we'll stick around until the last of them completes, use shared_ptr</phrase>
- <phrase role="comment">// anyway because it's easier to be confident about lifespan issues.</phrase>
- <phrase role="keyword">auto</phrase> <phrase role="identifier">barrier</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">barrier</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">count</phrase> <phrase role="special">+</phrase> <phrase role="number">1</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">wait_all_simple_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">barrier</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">barrier</phrase><phrase role="special">-></phrase><phrase role="identifier">wait</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- As stated above, the only difference between <code><phrase role="identifier">wait_all_simple_impl</phrase><phrase
- role="special">()</phrase></code> and <link linkend="wait_first_simple_impl"><code><phrase
- role="identifier">wait_first_simple_impl</phrase><phrase role="special">()</phrase></code></link>
- is that the former calls <code><phrase role="identifier">barrier</phrase><phrase
- role="special">::</phrase><phrase role="identifier">wait</phrase><phrase
- role="special">()</phrase></code> rather than <code><phrase role="identifier">Done</phrase><phrase
- role="special">::</phrase><phrase role="identifier">notify</phrase><phrase
- role="special">()</phrase></code>:
- </para>
- <para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait_all_simple_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">barrier</phrase> <phrase role="special">></phrase> <phrase role="identifier">barrier</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">bind</phrase><phrase role="special">(</phrase>
- <phrase role="special">[](</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">barrier</phrase> <phrase role="special">></phrase> <phrase role="special">&</phrase> <phrase role="identifier">barrier</phrase><phrase role="special">,</phrase>
- <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">decay</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="special">&</phrase> <phrase role="identifier">function</phrase><phrase role="special">)</phrase> <phrase role="keyword">mutable</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">function</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">barrier</phrase><phrase role="special">-></phrase><phrase role="identifier">wait</phrase><phrase role="special">();</phrase>
- <phrase role="special">},</phrase>
- <phrase role="identifier">barrier</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">function</phrase><phrase role="special">)</phrase>
- <phrase role="special">)).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">wait_all_simple_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">barrier</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- You might call it like this:
- </para>
- <para>
- <programlisting><phrase role="identifier">wait_all_simple</phrase><phrase role="special">(</phrase>
- <phrase role="special">[](){</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"was_long"</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"was_medium"</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"was_short"</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
- </programlisting>
- </para>
- <para>
- Control will not return from the <code><phrase role="identifier">wait_all_simple</phrase><phrase
- role="special">()</phrase></code> call until the last of its task functions
- has completed.
- </para>
- </section>
- <section id="fiber.when_any.when_all_functionality.when_all__return_values">
- <title><link linkend="fiber.when_any.when_all_functionality.when_all__return_values">when_all,
- return values</link></title>
- <para>
- As soon as we want to collect return values from all the task functions,
- we can see right away how to reuse <link linkend="wait_first_value"><code><phrase
- role="identifier">wait_first_value</phrase><phrase role="special">()</phrase></code></link>'s
- queue<T> for the purpose. All we have to do is avoid closing it after
- the first value!
- </para>
- <para>
- But in fact, collecting multiple values raises an interesting question:
- do we <emphasis>really</emphasis> want to wait until the slowest of them
- has arrived? Wouldn't we rather process each result as soon as it becomes
- available?
- </para>
- <para>
- Fortunately we can present both APIs. Let's define <code><phrase role="identifier">wait_all_values_source</phrase><phrase
- role="special">()</phrase></code> to return <code><phrase role="identifier">shared_ptr</phrase><phrase
- role="special"><</phrase><phrase role="identifier">buffered_channel</phrase><phrase
- role="special"><</phrase><phrase role="identifier">T</phrase><phrase
- role="special">>></phrase></code>.
- </para>
- <para>
- <anchor id="wait_all_values"/>Given <code><phrase role="identifier">wait_all_values_source</phrase><phrase
- role="special">()</phrase></code>, it's straightforward to implement <code><phrase
- role="identifier">wait_all_values</phrase><phrase role="special">()</phrase></code>:
- </para>
- <para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">wait_all_values</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">count</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase> <phrase role="special">+</phrase> <phrase role="keyword">sizeof</phrase> <phrase role="special">...</phrase> <phrase role="special">(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="identifier">return_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">vector_t</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">vector_t</phrase> <phrase role="identifier">results</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">results</phrase><phrase role="special">.</phrase><phrase role="identifier">reserve</phrase><phrase role="special">(</phrase> <phrase role="identifier">count</phrase><phrase role="special">);</phrase>
- <phrase role="comment">// get channel</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></phrase> <phrase role="special">></phrase> <phrase role="identifier">chan</phrase> <phrase role="special">=</phrase>
- <phrase role="identifier">wait_all_values_source</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">function</phrase><phrase role="special">),</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// fill results vector</phrase>
- <phrase role="identifier">return_t</phrase> <phrase role="identifier">value</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">channel_op_status</phrase><phrase role="special">::</phrase><phrase role="identifier">success</phrase> <phrase role="special">==</phrase> <phrase role="identifier">chan</phrase><phrase role="special">-></phrase><phrase role="identifier">pop</phrase><phrase role="special">(</phrase><phrase role="identifier">value</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">results</phrase><phrase role="special">.</phrase><phrase role="identifier">push_back</phrase><phrase role="special">(</phrase> <phrase role="identifier">value</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// return vector to caller</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">results</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- It might be called like this:
- </para>
- <para>
- <programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></phrase> <phrase role="identifier">values</phrase> <phrase role="special">=</phrase>
- <phrase role="identifier">wait_all_values</phrase><phrase role="special">(</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wav_late"</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wav_middle"</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wav_early"</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
- </programlisting>
- </para>
- <para>
- As you can see from the loop in <code><phrase role="identifier">wait_all_values</phrase><phrase
- role="special">()</phrase></code>, instead of requiring its caller to count
- values, we define <code><phrase role="identifier">wait_all_values_source</phrase><phrase
- role="special">()</phrase></code> to <link linkend="buffered_channel_close"><code>buffered_channel::close()</code></link> the
- queue when done. But how do we do that? Each producer fiber is independent.
- It has no idea whether it is the last one to <link linkend="buffered_channel_push"><code>buffered_channel::push()</code></link> a
- value.
- </para>
- <para>
- <anchor id="wait_nqueue"/>We can address that problem with a counting façade
- for the <code><phrase role="identifier">queue</phrase><phrase role="special"><></phrase></code>.
- In fact, our façade need only support the producer end of the queue.
- </para>
- <para>
- [wait_nqueue]
- </para>
- <para>
- <anchor id="wait_all_values_source"/>Armed with <code><phrase role="identifier">nqueue</phrase><phrase
- role="special"><></phrase></code>, we can implement <code><phrase
- role="identifier">wait_all_values_source</phrase><phrase role="special">()</phrase></code>.
- It starts just like <link linkend="wait_first_value"><code><phrase role="identifier">wait_first_value</phrase><phrase
- role="special">()</phrase></code></link>. The difference is that we wrap
- the <code><phrase role="identifier">queue</phrase><phrase role="special"><</phrase><phrase
- role="identifier">T</phrase><phrase role="special">></phrase></code>
- with an <code><phrase role="identifier">nqueue</phrase><phrase role="special"><</phrase><phrase
- role="identifier">T</phrase><phrase role="special">></phrase></code>
- to pass to the producer fibers.
- </para>
- <para>
- Then, of course, instead of popping the first value, closing the queue
- and returning it, we simply return the <code><phrase role="identifier">shared_ptr</phrase><phrase
- role="special"><</phrase><phrase role="identifier">queue</phrase><phrase
- role="special"><</phrase><phrase role="identifier">T</phrase><phrase
- role="special">>></phrase></code>.
- </para>
- <para>
- <programlisting><phrase role="comment">// Return a shared_ptr<buffered_channel<T>> from which the caller can</phrase>
- <phrase role="comment">// retrieve each new result as it arrives, until 'closed'.</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="special">></phrase> <phrase role="special">></phrase>
- <phrase role="identifier">wait_all_values_source</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">count</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase> <phrase role="special">+</phrase> <phrase role="keyword">sizeof</phrase> <phrase role="special">...</phrase> <phrase role="special">(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="identifier">return_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
- <phrase role="comment">// make the channel</phrase>
- <phrase role="keyword">auto</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special"><</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">>(</phrase> <phrase role="number">64</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// and make an nchannel facade to close it after 'count' items</phrase>
- <phrase role="keyword">auto</phrase> <phrase role="identifier">ncp</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special"><</phrase> <phrase role="identifier">nchannel</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></phrase> <phrase role="special">>(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">,</phrase> <phrase role="identifier">count</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// pass that nchannel facade to all the relevant fibers</phrase>
- <phrase role="identifier">wait_all_values_impl</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">ncp</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">function</phrase><phrase role="special">),</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// then return the channel for consumer</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- For example:
- </para>
- <para>
- <programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></phrase> <phrase role="special">></phrase> <phrase role="identifier">chan</phrase> <phrase role="special">=</phrase>
- <phrase role="identifier">wait_all_values_source</phrase><phrase role="special">(</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wavs_third"</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wavs_second"</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wavs_first"</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">value</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">channel_op_status</phrase><phrase role="special">::</phrase><phrase role="identifier">success</phrase> <phrase role="special">==</phrase> <phrase role="identifier">chan</phrase><phrase role="special">-></phrase><phrase role="identifier">pop</phrase><phrase role="special">(</phrase><phrase role="identifier">value</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"wait_all_values_source() => '"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">value</phrase>
- <phrase role="special"><<</phrase> <phrase role="string">"'"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- <anchor id="wait_all_values_impl"/><code><phrase role="identifier">wait_all_values_impl</phrase><phrase
- role="special">()</phrase></code> really is just like <link linkend="wait_first_value_impl"><code><phrase
- role="identifier">wait_first_value_impl</phrase><phrase role="special">()</phrase></code></link>
- except for the use of <code><phrase role="identifier">nqueue</phrase><phrase
- role="special"><</phrase><phrase role="identifier">T</phrase><phrase
- role="special">></phrase></code> rather than <code><phrase role="identifier">queue</phrase><phrase
- role="special"><</phrase><phrase role="identifier">T</phrase><phrase
- role="special">></phrase></code>:
- </para>
- <para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">T</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">></phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">wait_all_values_impl</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special"><</phrase> <phrase role="identifier">nchannel</phrase><phrase role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase role="special">></phrase> <phrase role="special">></phrase> <phrase role="identifier">chan</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="special">[</phrase><phrase role="identifier">chan</phrase><phrase role="special">,</phrase> <phrase role="identifier">function</phrase><phrase role="special">](){</phrase>
- <phrase role="identifier">chan</phrase><phrase role="special">-></phrase><phrase role="identifier">push</phrase><phrase role="special">(</phrase><phrase role="identifier">function</phrase><phrase role="special">());</phrase>
- <phrase role="special">}).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- </section>
- <section id="fiber.when_any.when_all_functionality.when_all_until_first_exception">
- <title><link linkend="fiber.when_any.when_all_functionality.when_all_until_first_exception">when_all
- until first exception</link></title>
- <para>
- Naturally, just as with <link linkend="wait_first_outcome"><code><phrase
- role="identifier">wait_first_outcome</phrase><phrase role="special">()</phrase></code></link>,
- we can elaborate <link linkend="wait_all_values"><code><phrase role="identifier">wait_all_values</phrase><phrase
- role="special">()</phrase></code></link> and <link linkend="wait_all_values_source"><code><phrase
- role="identifier">wait_all_values_source</phrase><phrase role="special">()</phrase></code></link>
- by passing <code><phrase role="identifier">future</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">T</phrase> <phrase role="special">></phrase></code>
- instead of plain <code><phrase role="identifier">T</phrase></code>.
- </para>
- <para>
- <anchor id="wait_all_until_error"/><code><phrase role="identifier">wait_all_until_error</phrase><phrase
- role="special">()</phrase></code> pops that <code><phrase role="identifier">future</phrase><phrase
- role="special"><</phrase> <phrase role="identifier">T</phrase> <phrase
- role="special">></phrase></code> and calls its <link linkend="future_get"><code>future::get()</code></link>:
- </para>
- <para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">wait_all_until_error</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">count</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase> <phrase role="special">+</phrase> <phrase role="keyword">sizeof</phrase> <phrase role="special">...</phrase> <phrase role="special">(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="identifier">return_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">future_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">vector_t</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">vector_t</phrase> <phrase role="identifier">results</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">results</phrase><phrase role="special">.</phrase><phrase role="identifier">reserve</phrase><phrase role="special">(</phrase> <phrase role="identifier">count</phrase><phrase role="special">);</phrase>
- <phrase role="comment">// get channel</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">></phrase> <phrase role="special">></phrase> <phrase role="identifier">chan</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">wait_all_until_error_source</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">function</phrase><phrase role="special">),</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// fill results vector</phrase>
- <phrase role="identifier">future_t</phrase> <phrase role="identifier">future</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">channel_op_status</phrase><phrase role="special">::</phrase><phrase role="identifier">success</phrase> <phrase role="special">==</phrase> <phrase role="identifier">chan</phrase><phrase role="special">-></phrase><phrase role="identifier">pop</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">results</phrase><phrase role="special">.</phrase><phrase role="identifier">push_back</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// return vector to caller</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">results</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- For example:
- </para>
- <para>
- <programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">thrown</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">try</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></phrase> <phrase role="identifier">values</phrase> <phrase role="special">=</phrase> <phrase role="identifier">wait_all_until_error</phrase><phrase role="special">(</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"waue_late"</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"waue_middle"</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">,</phrase> <phrase role="keyword">true</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"waue_early"</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
- <phrase role="special">}</phrase> <phrase role="keyword">catch</phrase> <phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">e</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">thrown</phrase> <phrase role="special">=</phrase> <phrase role="identifier">e</phrase><phrase role="special">.</phrase><phrase role="identifier">what</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"wait_all_until_error(fail) threw '"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">thrown</phrase>
- <phrase role="special"><<</phrase> <phrase role="string">"'"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
- </programlisting>
- </para>
- <para>
- <anchor id="wait_all_until_error_source"/>Naturally this complicates the
- API for <code><phrase role="identifier">wait_all_until_error_source</phrase><phrase
- role="special">()</phrase></code>. The caller must both retrieve a <code><phrase
- role="identifier">future</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">T</phrase> <phrase role="special">></phrase></code>
- and call its <code><phrase role="identifier">get</phrase><phrase role="special">()</phrase></code>
- method. It would, of course, be possible to return a façade over the consumer
- end of the queue that would implicitly perform the <code><phrase role="identifier">get</phrase><phrase
- role="special">()</phrase></code> and return a simple <code><phrase role="identifier">T</phrase></code>
- (or throw).
- </para>
- <para>
- The implementation is just as you would expect. Notice, however, that we
- can reuse <link linkend="wait_first_outcome_impl"><code><phrase role="identifier">wait_first_outcome_impl</phrase><phrase
- role="special">()</phrase></code></link>, passing the <code><phrase role="identifier">nqueue</phrase><phrase
- role="special"><</phrase><phrase role="identifier">T</phrase><phrase
- role="special">></phrase></code> rather than <code><phrase role="identifier">queue</phrase><phrase
- role="special"><</phrase><phrase role="identifier">T</phrase><phrase
- role="special">></phrase></code>.
- </para>
- <para>
- <programlisting><phrase role="comment">// Return a shared_ptr<buffered_channel<future<T>>> from which the caller can</phrase>
- <phrase role="comment">// get() each new result as it arrives, until 'closed'.</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special"><</phrase>
- <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="special">></phrase> <phrase role="special">></phrase> <phrase role="special">></phrase>
- <phrase role="identifier">wait_all_until_error_source</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">count</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase> <phrase role="special">+</phrase> <phrase role="keyword">sizeof</phrase> <phrase role="special">...</phrase> <phrase role="special">(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="identifier">return_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">future_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">channel_t</phrase><phrase role="special">;</phrase>
- <phrase role="comment">// make the channel</phrase>
- <phrase role="keyword">auto</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special"><</phrase> <phrase role="identifier">channel_t</phrase> <phrase role="special">>(</phrase> <phrase role="number">64</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// and make an nchannel facade to close it after 'count' items</phrase>
- <phrase role="keyword">auto</phrase> <phrase role="identifier">ncp</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special"><</phrase> <phrase role="identifier">nchannel</phrase><phrase role="special"><</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">></phrase> <phrase role="special">>(</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">,</phrase> <phrase role="identifier">count</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// pass that nchannel facade to all the relevant fibers</phrase>
- <phrase role="identifier">wait_first_outcome_impl</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">ncp</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">function</phrase><phrase role="special">),</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// then return the channel for consumer</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">chanp</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- For example:
- </para>
- <para>
- <programlisting><phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></phrase> <phrase role="identifier">future_t</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">></phrase> <phrase role="special">></phrase> <phrase role="identifier">chan</phrase> <phrase role="special">=</phrase>
- <phrase role="identifier">wait_all_until_error_source</phrase><phrase role="special">(</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wauess_third"</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wauess_second"</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wauess_first"</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
- <phrase role="identifier">future_t</phrase> <phrase role="identifier">future</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">channel_op_status</phrase><phrase role="special">::</phrase><phrase role="identifier">success</phrase> <phrase role="special">==</phrase> <phrase role="identifier">chan</phrase><phrase role="special">-></phrase><phrase role="identifier">pop</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">value</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"wait_all_until_error_source(success) => '"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">value</phrase>
- <phrase role="special"><<</phrase> <phrase role="string">"'"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- </section>
- <section id="fiber.when_any.when_all_functionality.wait_all__collecting_all_exceptions">
- <title><link linkend="fiber.when_any.when_all_functionality.wait_all__collecting_all_exceptions">wait_all,
- collecting all exceptions</link></title>
- <para>
- <anchor id="wait_all_collect_errors"/>Given <link linkend="wait_all_until_error_source"><code><phrase
- role="identifier">wait_all_until_error_source</phrase><phrase role="special">()</phrase></code></link>,
- it might be more reasonable to make a <code><phrase role="identifier">wait_all_</phrase><phrase
- role="special">...()</phrase></code> that collects <emphasis>all</emphasis>
- errors instead of presenting only the first:
- </para>
- <para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">wait_all_collect_errors</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">function</phrase><phrase role="special">,</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">size_t</phrase> <phrase role="identifier">count</phrase><phrase role="special">(</phrase> <phrase role="number">1</phrase> <phrase role="special">+</phrase> <phrase role="keyword">sizeof</phrase> <phrase role="special">...</phrase> <phrase role="special">(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">result_of</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase><phrase role="special">()</phrase> <phrase role="special">>::</phrase><phrase role="identifier">type</phrase> <phrase role="identifier">return_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">future</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">future_t</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">return_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">vector_t</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">vector_t</phrase> <phrase role="identifier">results</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">results</phrase><phrase role="special">.</phrase><phrase role="identifier">reserve</phrase><phrase role="special">(</phrase> <phrase role="identifier">count</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">exception_list</phrase> <phrase role="identifier">exceptions</phrase><phrase role="special">(</phrase><phrase role="string">"wait_all_collect_errors() exceptions"</phrase><phrase role="special">);</phrase>
- <phrase role="comment">// get channel</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special"><</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase> <phrase role="identifier">future_t</phrase> <phrase role="special">></phrase> <phrase role="special">></phrase> <phrase role="identifier">chan</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">wait_all_until_error_source</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">function</phrase><phrase role="special">),</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// fill results and/or exceptions vectors</phrase>
- <phrase role="identifier">future_t</phrase> <phrase role="identifier">future</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">channel_op_status</phrase><phrase role="special">::</phrase><phrase role="identifier">success</phrase> <phrase role="special">==</phrase> <phrase role="identifier">chan</phrase><phrase role="special">-></phrase><phrase role="identifier">pop</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">exception_ptr</phrase> <phrase role="identifier">exp</phrase> <phrase role="special">=</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get_exception_ptr</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">exp</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">results</phrase><phrase role="special">.</phrase><phrase role="identifier">push_back</phrase><phrase role="special">(</phrase> <phrase role="identifier">future</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="special">}</phrase> <phrase role="keyword">else</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">exceptions</phrase><phrase role="special">.</phrase><phrase role="identifier">add</phrase><phrase role="special">(</phrase> <phrase role="identifier">exp</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// if there were any exceptions, throw</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">exceptions</phrase><phrase role="special">.</phrase><phrase role="identifier">size</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">throw</phrase> <phrase role="identifier">exceptions</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// no exceptions: return vector to caller</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">results</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- The implementation is a simple variation on <link linkend="wait_first_success"><code><phrase
- role="identifier">wait_first_success</phrase><phrase role="special">()</phrase></code></link>,
- using the same <link linkend="exception_list"><code><phrase role="identifier">exception_list</phrase></code></link>
- exception class.
- </para>
- </section>
- <section id="fiber.when_any.when_all_functionality.when_all__heterogeneous_types">
- <title><link linkend="fiber.when_any.when_all_functionality.when_all__heterogeneous_types">when_all,
- heterogeneous types</link></title>
- <para>
- But what about the case when we must wait for all results of different
- types?
- </para>
- <para>
- We can present an API that is frankly quite cool. Consider a sample struct:
- </para>
- <para>
- <programlisting><phrase role="keyword">struct</phrase> <phrase role="identifier">Data</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">str</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">double</phrase> <phrase role="identifier">inexact</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">exact</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">friend</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ostream</phrase><phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special"><<(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ostream</phrase><phrase role="special">&</phrase> <phrase role="identifier">out</phrase><phrase role="special">,</phrase> <phrase role="identifier">Data</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">data</phrase><phrase role="special">);</phrase>
- <phrase role="special">...</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <para>
- Let's fill its members from task functions all running concurrently:
- </para>
- <para>
- <programlisting><phrase role="identifier">Data</phrase> <phrase role="identifier">data</phrase> <phrase role="special">=</phrase> <phrase role="identifier">wait_all_members</phrase><phrase role="special"><</phrase> <phrase role="identifier">Data</phrase> <phrase role="special">>(</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wams_left"</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="number">3.14</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="number">17</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"wait_all_members<Data>(success) => "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">data</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
- </programlisting>
- </para>
- <para>
- Note that for this case, we abandon the notion of capturing the earliest
- result first, and so on: we must fill exactly the passed struct in left-to-right
- order.
- </para>
- <para>
- That permits a beautifully simple implementation:
- </para>
- <para>
- <programlisting><phrase role="comment">// Explicitly pass Result. This can be any type capable of being initialized</phrase>
- <phrase role="comment">// from the results of the passed functions, such as a struct.</phrase>
- <phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Result</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">Result</phrase> <phrase role="identifier">wait_all_members</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// Run each of the passed functions on a separate fiber, passing all their</phrase>
- <phrase role="comment">// futures to helper function for processing.</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">wait_all_members_get</phrase><phrase role="special"><</phrase> <phrase role="identifier">Result</phrase> <phrase role="special">>(</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">async</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">forward</phrase><phrase role="special"><</phrase> <phrase role="identifier">Fns</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">functions</phrase><phrase role="special">)</phrase> <phrase role="special">)</phrase> <phrase role="special">...</phrase> <phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Result</phrase><phrase role="special">,</phrase> <phrase role="keyword">typename</phrase> <phrase role="special">...</phrase> <phrase role="identifier">Futures</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">Result</phrase> <phrase role="identifier">wait_all_members_get</phrase><phrase role="special">(</phrase> <phrase role="identifier">Futures</phrase> <phrase role="special">&&</phrase> <phrase role="special">...</phrase> <phrase role="identifier">futures</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// Fetch the results from the passed futures into Result's initializer</phrase>
- <phrase role="comment">// list. It's true that the get() calls here will block the implicit</phrase>
- <phrase role="comment">// iteration over futures -- but that doesn't matter because we won't be</phrase>
- <phrase role="comment">// done until the slowest of them finishes anyway. As results are</phrase>
- <phrase role="comment">// processed in argument-list order rather than order of completion, the</phrase>
- <phrase role="comment">// leftmost get() to throw an exception will cause that exception to</phrase>
- <phrase role="comment">// propagate to the caller.</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">Result</phrase><phrase role="special">{</phrase> <phrase role="identifier">futures</phrase><phrase role="special">.</phrase><phrase role="identifier">get</phrase><phrase role="special">()</phrase> <phrase role="special">...</phrase> <phrase role="special">};</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- It is tempting to try to implement <code><phrase role="identifier">wait_all_members</phrase><phrase
- role="special">()</phrase></code> as a one-liner like this:
- </para>
- <programlisting><phrase role="keyword">return</phrase> <phrase role="identifier">Result</phrase><phrase role="special">{</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">async</phrase><phrase role="special">(</phrase><phrase role="identifier">functions</phrase><phrase role="special">).</phrase><phrase role="identifier">get</phrase><phrase role="special">()...</phrase> <phrase role="special">};</phrase>
- </programlisting>
- <para>
- The trouble with this tactic is that it would serialize all the task functions.
- The runtime makes a single pass through <code><phrase role="identifier">functions</phrase></code>,
- calling <link linkend="fibers_async"><code>fibers::async()</code></link> for each and then immediately calling
- <link linkend="future_get"><code>future::get()</code></link> on its returned <code><phrase role="identifier">future</phrase><phrase
- role="special"><></phrase></code>. That blocks the implicit loop.
- The above is almost equivalent to writing:
- </para>
- <programlisting><phrase role="keyword">return</phrase> <phrase role="identifier">Result</phrase><phrase role="special">{</phrase> <phrase role="identifier">functions</phrase><phrase role="special">()...</phrase> <phrase role="special">};</phrase>
- </programlisting>
- <para>
- in which, of course, there is no concurrency at all.
- </para>
- <para>
- Passing the argument pack through a function-call boundary (<code><phrase
- role="identifier">wait_all_members_get</phrase><phrase role="special">()</phrase></code>)
- forces the runtime to make <emphasis>two</emphasis> passes: one in <code><phrase
- role="identifier">wait_all_members</phrase><phrase role="special">()</phrase></code>
- to collect the <code><phrase role="identifier">future</phrase><phrase role="special"><></phrase></code>s
- from all the <code><phrase role="identifier">async</phrase><phrase role="special">()</phrase></code>
- calls, the second in <code><phrase role="identifier">wait_all_members_get</phrase><phrase
- role="special">()</phrase></code> to fetch each of the results.
- </para>
- <para>
- As noted in comments, within the <code><phrase role="identifier">wait_all_members_get</phrase><phrase
- role="special">()</phrase></code> parameter pack expansion pass, the blocking
- behavior of <code><phrase role="identifier">get</phrase><phrase role="special">()</phrase></code>
- becomes irrelevant. Along the way, we will hit the <code><phrase role="identifier">get</phrase><phrase
- role="special">()</phrase></code> for the slowest task function; after
- that every subsequent <code><phrase role="identifier">get</phrase><phrase
- role="special">()</phrase></code> will complete in trivial time.
- </para>
- <para>
- By the way, we could also use this same API to fill a vector or other collection:
- </para>
- <para>
- <programlisting><phrase role="comment">// If we don't care about obtaining results as soon as they arrive, and we</phrase>
- <phrase role="comment">// prefer a result vector in passed argument order rather than completion</phrase>
- <phrase role="comment">// order, wait_all_members() is another possible implementation of</phrase>
- <phrase role="comment">// wait_all_until_error().</phrase>
- <phrase role="keyword">auto</phrase> <phrase role="identifier">strings</phrase> <phrase role="special">=</phrase> <phrase role="identifier">wait_all_members</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="special">></phrase> <phrase role="special">>(</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wamv_left"</phrase><phrase role="special">,</phrase> <phrase role="number">150</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wamv_middle"</phrase><phrase role="special">,</phrase> <phrase role="number">100</phrase><phrase role="special">);</phrase> <phrase role="special">},</phrase>
- <phrase role="special">[](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">sleeper</phrase><phrase role="special">(</phrase><phrase role="string">"wamv_right"</phrase><phrase role="special">,</phrase> <phrase role="number">50</phrase><phrase role="special">);</phrase> <phrase role="special">});</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"wait_all_members<vector>() =>"</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">str</phrase> <phrase role="special">:</phrase> <phrase role="identifier">strings</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">" '"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">str</phrase> <phrase role="special"><<</phrase> <phrase role="string">"'"</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
- </programlisting>
- </para>
- </section>
- </section>
- </section>
- <section id="fiber.integration">
- <title><anchor id="integration"/><link linkend="fiber.integration">Sharing a
- Thread with Another Main Loop</link></title>
- <section id="fiber.integration.overview">
- <title><link linkend="fiber.integration.overview">Overview</link></title>
- <para>
- As always with cooperative concurrency, it is important not to let any one
- fiber monopolize the processor too long: that could <quote>starve</quote>
- other ready fibers. This section discusses a couple of solutions.
- </para>
- </section>
- <section id="fiber.integration.event_driven_program">
- <title><link linkend="fiber.integration.event_driven_program">Event-Driven
- Program</link></title>
- <para>
- Consider a classic event-driven program, organized around a main loop that
- fetches and dispatches incoming I/O events. You are introducing <emphasis
- role="bold">Boost.Fiber</emphasis> because certain asynchronous I/O sequences
- are logically sequential, and for those you want to write and maintain code
- that looks and acts sequential.
- </para>
- <para>
- You are launching fibers on the application’s main thread because certain
- of their actions will affect its user interface, and the application’s UI
- framework permits UI operations only on the main thread. Or perhaps those
- fibers need access to main-thread data, and it would be too expensive in
- runtime (or development time) to robustly defend every such data item with
- thread synchronization primitives.
- </para>
- <para>
- You must ensure that the application’s main loop <emphasis>itself</emphasis>
- doesn’t monopolize the processor: that the fibers it launches will get the
- CPU cycles they need.
- </para>
- <para>
- The solution is the same as for any fiber that might claim the CPU for an
- extended time: introduce calls to <link linkend="this_fiber_yield"><code>this_fiber::yield()</code></link>. The
- most straightforward approach is to call <code><phrase role="identifier">yield</phrase><phrase
- role="special">()</phrase></code> on every iteration of your existing main
- loop. In effect, this unifies the application’s main loop with <emphasis role="bold">Boost.Fiber</emphasis>’s
- internal main loop. <code><phrase role="identifier">yield</phrase><phrase
- role="special">()</phrase></code> allows the fiber manager to run any fibers
- that have become ready since the previous iteration of the application’s main
- loop. When these fibers have had a turn, control passes to the thread’s main
- fiber, which returns from <code><phrase role="identifier">yield</phrase><phrase
- role="special">()</phrase></code> and resumes the application’s main loop.
- </para>
- </section>
- <section id="fiber.integration.embedded_main_loop">
- <title><anchor id="embedded_main_loop"/><link linkend="fiber.integration.embedded_main_loop">Embedded
- Main Loop</link></title>
- <para>
- More challenging is when the application’s main loop is embedded in some other
- library or framework. Such an application will typically, after performing
- all necessary setup, pass control to some form of <code><phrase role="identifier">run</phrase><phrase
- role="special">()</phrase></code> function from which control does not return
- until application shutdown.
- </para>
- <para>
- A <ulink url="http://www.boost.org/doc/libs/release/libs/asio/index.html">Boost.Asio</ulink>
- program might call <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/run.html"><code><phrase
- role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
- role="identifier">run</phrase><phrase role="special">()</phrase></code></ulink>
- in this way.
- </para>
- <para>
- In general, the trick is to arrange to pass control to <link linkend="this_fiber_yield"><code>this_fiber::yield()</code></link> frequently.
- You could use an <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/high_resolution_timer.html">Asio
- timer</ulink> for that purpose. You could instantiate the timer, arranging
- to call a handler function when the timer expires. The handler function could
- call <code><phrase role="identifier">yield</phrase><phrase role="special">()</phrase></code>,
- then reset the timer and arrange to wake up again on its next expiration.
- </para>
- <para>
- Since, in this thought experiment, we always pass control to the fiber manager
- via <code><phrase role="identifier">yield</phrase><phrase role="special">()</phrase></code>,
- the calling fiber is never blocked. Therefore there is always at least one
- ready fiber. Therefore the fiber manager never calls <link linkend="algorithm_suspend_until"><code>algorithm::suspend_until()</code></link>.
- </para>
- <para>
- Using <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/post.html"><code><phrase
- role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
- role="identifier">post</phrase><phrase role="special">()</phrase></code></ulink>
- instead of setting a timer for some nonzero interval would be unfriendly
- to other threads. When all I/O is pending and all fibers are blocked, the
- io_service and the fiber manager would simply spin the CPU, passing control
- back and forth to each other. Using a timer allows tuning the responsiveness
- of this thread relative to others.
- </para>
- </section>
- <section id="fiber.integration.deeper_dive_into___boost_asio__">
- <title><link linkend="fiber.integration.deeper_dive_into___boost_asio__">Deeper
- Dive into <ulink url="http://www.boost.org/doc/libs/release/libs/asio/index.html">Boost.Asio</ulink></link></title>
- <para>
- By now the alert reader is thinking: but surely, with Asio in particular,
- we ought to be able to do much better than periodic polling pings!
- </para>
- <para>
- This turns out to be surprisingly tricky. We present a possible approach
- in <ulink url="../../examples/asio/round_robin.hpp"><code><phrase role="identifier">examples</phrase><phrase
- role="special">/</phrase><phrase role="identifier">asio</phrase><phrase role="special">/</phrase><phrase
- role="identifier">round_robin</phrase><phrase role="special">.</phrase><phrase
- role="identifier">hpp</phrase></code></ulink>.
- </para>
- <para>
- One consequence of using <ulink url="http://www.boost.org/doc/libs/release/libs/asio/index.html">Boost.Asio</ulink>
- is that you must always let Asio suspend the running thread. Since Asio is
- aware of pending I/O requests, it can arrange to suspend the thread in such
- a way that the OS will wake it on I/O completion. No one else has sufficient
- knowledge.
- </para>
- <para>
- So the fiber scheduler must depend on Asio for suspension and resumption.
- It requires Asio handler calls to wake it.
- </para>
- <para>
- One dismaying implication is that we cannot support multiple threads calling
- <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/run.html"><code><phrase
- role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
- role="identifier">run</phrase><phrase role="special">()</phrase></code></ulink>
- on the same <code><phrase role="identifier">io_service</phrase></code> instance.
- The reason is that Asio provides no way to constrain a particular handler
- to be called only on a specified thread. A fiber scheduler instance is locked
- to a particular thread: that instance cannot manage any other thread’s fibers.
- Yet if we allow multiple threads to call <code><phrase role="identifier">io_service</phrase><phrase
- role="special">::</phrase><phrase role="identifier">run</phrase><phrase role="special">()</phrase></code>
- on the same <code><phrase role="identifier">io_service</phrase></code> instance,
- a fiber scheduler which needs to sleep can have no guarantee that it will
- reawaken in a timely manner. It can set an Asio timer, as described above
- — but that timer’s handler may well execute on a different thread!
- </para>
- <para>
- Another implication is that since an Asio-aware fiber scheduler (not to mention
- <link linkend="callbacks_asio"><code><phrase role="identifier">boost</phrase><phrase
- role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase
- role="special">::</phrase><phrase role="identifier">asio</phrase><phrase
- role="special">::</phrase><phrase role="identifier">yield</phrase></code></link>)
- depends on handler calls from the <code><phrase role="identifier">io_service</phrase></code>,
- it is the application’s responsibility to ensure that <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/stop.html"><code><phrase
- role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
- role="identifier">stop</phrase><phrase role="special">()</phrase></code></ulink>
- is not called until every fiber has terminated.
- </para>
- <para>
- It is easier to reason about the behavior of the presented <code><phrase
- role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
- role="identifier">round_robin</phrase></code> scheduler if we require that
- after initial setup, the thread’s main fiber is the fiber that calls <code><phrase
- role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
- role="identifier">run</phrase><phrase role="special">()</phrase></code>,
- so let’s impose that requirement.
- </para>
- <para>
- Naturally, the first thing we must do on each thread using a custom fiber
- scheduler is call <link linkend="use_scheduling_algorithm"><code>use_scheduling_algorithm()</code></link>. However,
- since <code><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
- role="identifier">round_robin</phrase></code> requires an <code><phrase role="identifier">io_service</phrase></code>
- instance, we must first declare that.
- </para>
- <para>
- <programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase> <phrase role="special">></phrase> <phrase role="identifier">io_svc</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">make_shared</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase> <phrase role="special">>();</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">round_robin</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">io_svc</phrase><phrase role="special">);</phrase>
- </programlisting>
- </para>
- <para>
- <code><phrase role="identifier">use_scheduling_algorithm</phrase><phrase
- role="special">()</phrase></code> instantiates <code><phrase role="identifier">asio</phrase><phrase
- role="special">::</phrase><phrase role="identifier">round_robin</phrase></code>,
- which naturally calls its constructor:
- </para>
- <para>
- <programlisting><phrase role="identifier">round_robin</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">io_svc</phrase><phrase role="special">)</phrase> <phrase role="special">:</phrase>
- <phrase role="identifier">io_svc_</phrase><phrase role="special">(</phrase> <phrase role="identifier">io_svc</phrase><phrase role="special">),</phrase>
- <phrase role="identifier">suspend_timer_</phrase><phrase role="special">(</phrase> <phrase role="special">*</phrase> <phrase role="identifier">io_svc_</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// We use add_service() very deliberately. This will throw</phrase>
- <phrase role="comment">// service_already_exists if you pass the same io_service instance to</phrase>
- <phrase role="comment">// more than one round_robin instance.</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">add_service</phrase><phrase role="special">(</phrase> <phrase role="special">*</phrase> <phrase role="identifier">io_svc_</phrase><phrase role="special">,</phrase> <phrase role="keyword">new</phrase> <phrase role="identifier">service</phrase><phrase role="special">(</phrase> <phrase role="special">*</phrase> <phrase role="identifier">io_svc_</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">io_svc_</phrase><phrase role="special">-></phrase><phrase role="identifier">post</phrase><phrase role="special">([</phrase><phrase role="keyword">this</phrase><phrase role="special">]()</phrase> <phrase role="keyword">mutable</phrase> <phrase role="special">{</phrase>
- </programlisting>
- </para>
- <para>
- <code><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
- role="identifier">round_robin</phrase></code> binds the passed <code><phrase
- role="identifier">io_service</phrase></code> pointer and initializes a <ulink
- url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/steady_timer.html"><code><phrase
- role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
- role="identifier">steady_timer</phrase></code></ulink>:
- </para>
- <para>
- <programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">shared_ptr</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase> <phrase role="special">></phrase> <phrase role="identifier">io_svc_</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_timer</phrase> <phrase role="identifier">suspend_timer_</phrase><phrase role="special">;</phrase>
- </programlisting>
- </para>
- <para>
- Then it calls <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/add_service.html"><code><phrase
- role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
- role="identifier">add_service</phrase><phrase role="special">()</phrase></code></ulink>
- with a nested <code><phrase role="identifier">service</phrase></code> struct:
- </para>
- <para>
- <programlisting><phrase role="keyword">struct</phrase> <phrase role="identifier">service</phrase> <phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase role="identifier">service</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">static</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase role="identifier">id</phrase> <phrase role="identifier">id</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_ptr</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase role="identifier">work</phrase> <phrase role="special">></phrase> <phrase role="identifier">work_</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">service</phrase><phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase> <phrase role="special">&</phrase> <phrase role="identifier">io_svc</phrase><phrase role="special">)</phrase> <phrase role="special">:</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase role="identifier">service</phrase><phrase role="special">(</phrase> <phrase role="identifier">io_svc</phrase><phrase role="special">),</phrase>
- <phrase role="identifier">work_</phrase><phrase role="special">{</phrase> <phrase role="keyword">new</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase role="identifier">work</phrase><phrase role="special">(</phrase> <phrase role="identifier">io_svc</phrase><phrase role="special">)</phrase> <phrase role="special">}</phrase> <phrase role="special">{</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="special">~</phrase><phrase role="identifier">service</phrase><phrase role="special">()</phrase> <phrase role="special">{}</phrase>
- <phrase role="identifier">service</phrase><phrase role="special">(</phrase> <phrase role="identifier">service</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">service</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">service</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">shutdown_service</phrase><phrase role="special">()</phrase> <phrase role="identifier">override</phrase> <phrase role="identifier">final</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">work_</phrase><phrase role="special">.</phrase><phrase role="identifier">reset</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <para>
- ... [asio_rr_service_bottom]
- </para>
- <para>
- The <code><phrase role="identifier">service</phrase></code> struct has a
- couple of roles.
- </para>
- <para>
- Its foremost role is to manage a <literal>std::unique_ptr<<ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service__work.html"><code><phrase
- role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
- role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
- role="identifier">work</phrase></code></ulink>></literal>. We want the
- <code><phrase role="identifier">io_service</phrase></code> instance to continue
- its main loop even when there is no pending Asio I/O.
- </para>
- <para>
- But when <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service__service/shutdown_service.html"><code><phrase
- role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
- role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
- role="identifier">service</phrase><phrase role="special">::</phrase><phrase
- role="identifier">shutdown_service</phrase><phrase role="special">()</phrase></code></ulink>
- is called, we discard the <code><phrase role="identifier">io_service</phrase><phrase
- role="special">::</phrase><phrase role="identifier">work</phrase></code>
- instance so the <code><phrase role="identifier">io_service</phrase></code>
- can shut down properly.
- </para>
- <para>
- Its other purpose is to <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/post.html"><code><phrase
- role="identifier">post</phrase><phrase role="special">()</phrase></code></ulink>
- a lambda (not yet shown). Let’s walk further through the example program before
- coming back to explain that lambda.
- </para>
- <para>
- The <code><phrase role="identifier">service</phrase></code> constructor returns
- to <code><phrase role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
- role="identifier">round_robin</phrase></code>’s constructor, which returns
- to <code><phrase role="identifier">use_scheduling_algorithm</phrase><phrase
- role="special">()</phrase></code>, which returns to the application code.
- </para>
- <para>
- Once it has called <code><phrase role="identifier">use_scheduling_algorithm</phrase><phrase
- role="special">()</phrase></code>, the application may now launch some number
- of fibers:
- </para>
- <para>
- <programlisting><phrase role="comment">// server</phrase>
- <phrase role="identifier">tcp</phrase><phrase role="special">::</phrase><phrase role="identifier">acceptor</phrase> <phrase role="identifier">a</phrase><phrase role="special">(</phrase> <phrase role="special">*</phrase> <phrase role="identifier">io_svc</phrase><phrase role="special">,</phrase> <phrase role="identifier">tcp</phrase><phrase role="special">::</phrase><phrase role="identifier">endpoint</phrase><phrase role="special">(</phrase> <phrase role="identifier">tcp</phrase><phrase role="special">::</phrase><phrase role="identifier">v4</phrase><phrase role="special">(),</phrase> <phrase role="number">9999</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">server</phrase><phrase role="special">,</phrase> <phrase role="identifier">io_svc</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ref</phrase><phrase role="special">(</phrase> <phrase role="identifier">a</phrase><phrase role="special">)</phrase> <phrase role="special">).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
- <phrase role="comment">// client</phrase>
- <phrase role="keyword">const</phrase> <phrase role="keyword">unsigned</phrase> <phrase role="identifier">iterations</phrase> <phrase role="special">=</phrase> <phrase role="number">2</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">const</phrase> <phrase role="keyword">unsigned</phrase> <phrase role="identifier">clients</phrase> <phrase role="special">=</phrase> <phrase role="number">3</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">barrier</phrase> <phrase role="identifier">b</phrase><phrase role="special">(</phrase> <phrase role="identifier">clients</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">unsigned</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special"><</phrase> <phrase role="identifier">clients</phrase><phrase role="special">;</phrase> <phrase role="special">++</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">(</phrase>
- <phrase role="identifier">client</phrase><phrase role="special">,</phrase> <phrase role="identifier">io_svc</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ref</phrase><phrase role="special">(</phrase> <phrase role="identifier">a</phrase><phrase role="special">),</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">ref</phrase><phrase role="special">(</phrase> <phrase role="identifier">b</phrase><phrase role="special">),</phrase> <phrase role="identifier">iterations</phrase><phrase role="special">).</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- Since we don’t specify a <link linkend="class_launch"><code>launch</code></link>, these fibers are ready to run,
- but have not yet been entered.
- </para>
- <para>
- Having set everything up, the application calls <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/run.html"><code><phrase
- role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
- role="identifier">run</phrase><phrase role="special">()</phrase></code></ulink>:
- </para>
- <para>
- <programlisting><phrase role="identifier">io_svc</phrase><phrase role="special">-></phrase><phrase role="identifier">run</phrase><phrase role="special">();</phrase>
- </programlisting>
- </para>
- <para>
- Now what?
- </para>
- <para>
- Because this <code><phrase role="identifier">io_service</phrase></code> instance
- owns an <code><phrase role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
- role="identifier">work</phrase></code> instance, <code><phrase role="identifier">run</phrase><phrase
- role="special">()</phrase></code> does not immediately return. But — none of
- the fibers that will perform actual work has even been entered yet!
- </para>
- <para>
- Without that initial <code><phrase role="identifier">post</phrase><phrase
- role="special">()</phrase></code> call in <code><phrase role="identifier">service</phrase></code>’s
- constructor, <emphasis>nothing</emphasis> would happen. The application would
- hang right here.
- </para>
- <para>
- So, what should the <code><phrase role="identifier">post</phrase><phrase
- role="special">()</phrase></code> handler execute? Simply <link linkend="this_fiber_yield"><code>this_fiber::yield()</code></link>?
- </para>
- <para>
- That would be a promising start. But we have no guarantee that any of the
- other fibers will initiate any Asio operations to keep the ball rolling.
- For all we know, every other fiber could reach a similar <code><phrase role="identifier">boost</phrase><phrase
- role="special">::</phrase><phrase role="identifier">this_fiber</phrase><phrase
- role="special">::</phrase><phrase role="identifier">yield</phrase><phrase
- role="special">()</phrase></code> call first. Control would return to the
- <code><phrase role="identifier">post</phrase><phrase role="special">()</phrase></code>
- handler, which would return to Asio, and... the application would hang.
- </para>
- <para>
- The <code><phrase role="identifier">post</phrase><phrase role="special">()</phrase></code>
- handler could <code><phrase role="identifier">post</phrase><phrase role="special">()</phrase></code>
- itself again. But as discussed in <link linkend="embedded_main_loop">the
- previous section</link>, once there are actual I/O operations in flight — once
- we reach a state in which no fiber is ready —
- that would cause the thread to
- spin.
- </para>
- <para>
- We could, of course, set an Asio timer — again as <link linkend="embedded_main_loop">previously
- discussed</link>. But in this <quote>deeper dive,</quote> we’re trying to
- do a little better.
- </para>
- <para>
- The key to doing better is that since we’re in a fiber, we can run an actual
- loop — not just a chain of callbacks. We can wait for <quote>something to happen</quote>
- by calling <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/run_one.html"><code><phrase
- role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
- role="identifier">run_one</phrase><phrase role="special">()</phrase></code></ulink>
- — or we can execute already-queued Asio handlers by calling <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/poll.html"><code><phrase
- role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
- role="identifier">poll</phrase><phrase role="special">()</phrase></code></ulink>.
- </para>
- <para>
- Here’s the body of the lambda passed to the <code><phrase role="identifier">post</phrase><phrase
- role="special">()</phrase></code> call.
- </para>
- <para>
- <programlisting> <phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">io_svc_</phrase><phrase role="special">-></phrase><phrase role="identifier">stopped</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// run all pending handlers in round_robin</phrase>
- <phrase role="keyword">while</phrase> <phrase role="special">(</phrase> <phrase role="identifier">io_svc_</phrase><phrase role="special">-></phrase><phrase role="identifier">poll</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="comment">// block this fiber till all pending (ready) fibers are processed</phrase>
- <phrase role="comment">// == round_robin::suspend_until() has been called</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">></phrase> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx_</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">cnd_</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase> <phrase role="keyword">else</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// run one handler inside io_service</phrase>
- <phrase role="comment">// if no handler available, block this thread</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">io_svc_</phrase><phrase role="special">-></phrase><phrase role="identifier">run_one</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">break</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- We want this loop to exit once the <code><phrase role="identifier">io_service</phrase></code>
- instance has been <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/stopped.html"><code><phrase
- role="identifier">stopped</phrase><phrase role="special">()</phrase></code></ulink>.
- </para>
- <para>
- As long as there are ready fibers, we interleave running ready Asio handlers
- with running ready fibers.
- </para>
- <para>
- If there are no ready fibers, we wait by calling <code><phrase role="identifier">run_one</phrase><phrase
- role="special">()</phrase></code>. Once any Asio handler has been called
- — no matter which — <code><phrase role="identifier">run_one</phrase><phrase role="special">()</phrase></code>
- returns. That handler may have transitioned some fiber to ready state, so
- we loop back to check again.
- </para>
- <para>
- (We won’t describe <code><phrase role="identifier">awakened</phrase><phrase
- role="special">()</phrase></code>, <code><phrase role="identifier">pick_next</phrase><phrase
- role="special">()</phrase></code> or <code><phrase role="identifier">has_ready_fibers</phrase><phrase
- role="special">()</phrase></code>, as these are just like <link linkend="round_robin_awakened"><code>round_robin::awakened()</code></link>,
- <link linkend="round_robin_pick_next"><code>round_robin::pick_next()</code></link> and <link linkend="round_robin_has_ready_fibers"><code>round_robin::has_ready_fibers()</code></link>.)
- </para>
- <para>
- That leaves <code><phrase role="identifier">suspend_until</phrase><phrase
- role="special">()</phrase></code> and <code><phrase role="identifier">notify</phrase><phrase
- role="special">()</phrase></code>.
- </para>
- <para>
- Doubtless you have been asking yourself: why are we calling <code><phrase
- role="identifier">io_service</phrase><phrase role="special">::</phrase><phrase
- role="identifier">run_one</phrase><phrase role="special">()</phrase></code>
- in the lambda loop? Why not call it in <code><phrase role="identifier">suspend_until</phrase><phrase
- role="special">()</phrase></code>, whose very API was designed for just such
- a purpose?
- </para>
- <para>
- Under normal circumstances, when the fiber manager finds no ready fibers,
- it calls <link linkend="algorithm_suspend_until"><code>algorithm::suspend_until()</code></link>. Why test <code><phrase
- role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase></code>
- in the lambda loop? Why not leverage the normal mechanism?
- </para>
- <para>
- The answer is: it matters who’s asking.
- </para>
- <para>
- Consider the lambda loop shown above. The only <emphasis role="bold">Boost.Fiber</emphasis>
- APIs it engages are <code><phrase role="identifier">has_ready_fibers</phrase><phrase
- role="special">()</phrase></code> and <link linkend="this_fiber_yield"><code>this_fiber::yield()</code></link>.
- <code><phrase role="identifier">yield</phrase><phrase role="special">()</phrase></code>
- does not <emphasis>block</emphasis> the calling fiber: the calling fiber
- does not become unready. It is immediately passed back to <link linkend="algorithm_awakened"><code>algorithm::awakened()</code></link>,
- to be resumed in its turn when all other ready fibers have had a chance to
- run. In other words: during a <code><phrase role="identifier">yield</phrase><phrase
- role="special">()</phrase></code> call, <emphasis>there is always at least
- one ready fiber.</emphasis>
- </para>
- <para>
- As long as this lambda loop is still running, the fiber manager does not
- call <code><phrase role="identifier">suspend_until</phrase><phrase role="special">()</phrase></code>
- because it always has a fiber ready to run.
- </para>
- <para>
- However, the lambda loop <emphasis>itself</emphasis> can detect the case
- when no <emphasis>other</emphasis> fibers are ready to run: the running fiber
- is not <emphasis>ready</emphasis> but <emphasis>running.</emphasis>
- </para>
- <para>
- That said, <code><phrase role="identifier">suspend_until</phrase><phrase
- role="special">()</phrase></code> and <code><phrase role="identifier">notify</phrase><phrase
- role="special">()</phrase></code> are in fact called during orderly shutdown
- processing, so let’s try a plausible implementation.
- </para>
- <para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// Set a timer so at least one handler will eventually fire, causing</phrase>
- <phrase role="comment">// run_one() to eventually return.</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="special">(</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">::</phrase><phrase role="identifier">max</phrase><phrase role="special">)()</phrase> <phrase role="special">!=</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// Each expires_at(time_point) call cancels any previous pending</phrase>
- <phrase role="comment">// call. We could inadvertently spin like this:</phrase>
- <phrase role="comment">// dispatcher calls suspend_until() with earliest wake time</phrase>
- <phrase role="comment">// suspend_until() sets suspend_timer_</phrase>
- <phrase role="comment">// lambda loop calls run_one()</phrase>
- <phrase role="comment">// some other asio handler runs before timer expires</phrase>
- <phrase role="comment">// run_one() returns to lambda loop</phrase>
- <phrase role="comment">// lambda loop yields to dispatcher</phrase>
- <phrase role="comment">// dispatcher finds no ready fibers</phrase>
- <phrase role="comment">// dispatcher calls suspend_until() with SAME wake time</phrase>
- <phrase role="comment">// suspend_until() sets suspend_timer_ to same time, canceling</phrase>
- <phrase role="comment">// previous async_wait()</phrase>
- <phrase role="comment">// lambda loop calls run_one()</phrase>
- <phrase role="comment">// asio calls suspend_timer_ handler with operation_aborted</phrase>
- <phrase role="comment">// run_one() returns to lambda loop... etc. etc.</phrase>
- <phrase role="comment">// So only actually set the timer when we're passed a DIFFERENT</phrase>
- <phrase role="comment">// abs_time value.</phrase>
- <phrase role="identifier">suspend_timer_</phrase><phrase role="special">.</phrase><phrase role="identifier">expires_at</phrase><phrase role="special">(</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">suspend_timer_</phrase><phrase role="special">.</phrase><phrase role="identifier">async_wait</phrase><phrase role="special">([](</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase> <phrase role="keyword">const</phrase><phrase role="special">&){</phrase>
- <phrase role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">yield</phrase><phrase role="special">();</phrase>
- <phrase role="special">});</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">cnd_</phrase><phrase role="special">.</phrase><phrase role="identifier">notify_one</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- As you might expect, <code><phrase role="identifier">suspend_until</phrase><phrase
- role="special">()</phrase></code> sets an <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/steady_timer.html"><code><phrase
- role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
- role="identifier">steady_timer</phrase></code></ulink> to <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/basic_waitable_timer/expires_at.html"><code><phrase
- role="identifier">expires_at</phrase><phrase role="special">()</phrase></code></ulink>
- the passed <ulink url="http://en.cppreference.com/w/cpp/chrono/steady_clock"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase
- role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase
- role="special">::</phrase><phrase role="identifier">time_point</phrase></code></ulink>.
- Usually.
- </para>
- <para>
- As indicated in comments, we avoid setting <code><phrase role="identifier">suspend_timer_</phrase></code>
- multiple times to the <emphasis>same</emphasis> <code><phrase role="identifier">time_point</phrase></code>
- value since every <code><phrase role="identifier">expires_at</phrase><phrase
- role="special">()</phrase></code> call cancels any previous <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/basic_waitable_timer/async_wait.html"><code><phrase
- role="identifier">async_wait</phrase><phrase role="special">()</phrase></code></ulink>
- call. There is a chance that we could spin. Reaching <code><phrase role="identifier">suspend_until</phrase><phrase
- role="special">()</phrase></code> means the fiber manager intends to yield
- the processor to Asio. Cancelling the previous <code><phrase role="identifier">async_wait</phrase><phrase
- role="special">()</phrase></code> call would fire its handler, causing <code><phrase
- role="identifier">run_one</phrase><phrase role="special">()</phrase></code>
- to return, potentially causing the fiber manager to call <code><phrase role="identifier">suspend_until</phrase><phrase
- role="special">()</phrase></code> again with the same <code><phrase role="identifier">time_point</phrase></code>
- value...
- </para>
- <para>
- Given that we suspend the thread by calling <code><phrase role="identifier">io_service</phrase><phrase
- role="special">::</phrase><phrase role="identifier">run_one</phrase><phrase
- role="special">()</phrase></code>, what’s important is that our <code><phrase
- role="identifier">async_wait</phrase><phrase role="special">()</phrase></code>
- call will cause a handler to run, which will cause <code><phrase role="identifier">run_one</phrase><phrase
- role="special">()</phrase></code> to return. It’s not so important specifically
- what that handler does.
- </para>
- <para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// Something has happened that should wake one or more fibers BEFORE</phrase>
- <phrase role="comment">// suspend_timer_ expires. Reset the timer to cause it to fire</phrase>
- <phrase role="comment">// immediately, causing the run_one() call to return. In theory we</phrase>
- <phrase role="comment">// could use cancel() because we don't care whether suspend_timer_'s</phrase>
- <phrase role="comment">// handler is called with operation_aborted or success. However --</phrase>
- <phrase role="comment">// cancel() doesn't change the expiration time, and we use</phrase>
- <phrase role="comment">// suspend_timer_'s expiration time to decide whether it's already</phrase>
- <phrase role="comment">// set. If suspend_until() set some specific wake time, then notify()</phrase>
- <phrase role="comment">// canceled it, then suspend_until() was called again with the same</phrase>
- <phrase role="comment">// wake time, it would match suspend_timer_'s expiration time and we'd</phrase>
- <phrase role="comment">// refrain from setting the timer. So instead of simply calling</phrase>
- <phrase role="comment">// cancel(), reset the timer, which cancels the pending sleep AND sets</phrase>
- <phrase role="comment">// a new expiration time. This will cause us to spin the loop twice --</phrase>
- <phrase role="comment">// once for the operation_aborted handler, once for timer expiration</phrase>
- <phrase role="comment">// -- but that shouldn't be a big problem.</phrase>
- <phrase role="identifier">suspend_timer_</phrase><phrase role="special">.</phrase><phrase role="identifier">async_wait</phrase><phrase role="special">([](</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">system</phrase><phrase role="special">::</phrase><phrase role="identifier">error_code</phrase> <phrase role="keyword">const</phrase><phrase role="special">&){</phrase>
- <phrase role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">yield</phrase><phrase role="special">();</phrase>
- <phrase role="special">});</phrase>
- <phrase role="identifier">suspend_timer_</phrase><phrase role="special">.</phrase><phrase role="identifier">expires_at</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">now</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- Since an <code><phrase role="identifier">expires_at</phrase><phrase role="special">()</phrase></code>
- call cancels any previous <code><phrase role="identifier">async_wait</phrase><phrase
- role="special">()</phrase></code> call, we can make <code><phrase role="identifier">notify</phrase><phrase
- role="special">()</phrase></code> simply call <code><phrase role="identifier">steady_timer</phrase><phrase
- role="special">::</phrase><phrase role="identifier">expires_at</phrase><phrase
- role="special">()</phrase></code>. That should cause the <code><phrase role="identifier">io_service</phrase></code>
- to call the <code><phrase role="identifier">async_wait</phrase><phrase role="special">()</phrase></code>
- handler with <code><phrase role="identifier">operation_aborted</phrase></code>.
- </para>
- <para>
- The comments in <code><phrase role="identifier">notify</phrase><phrase role="special">()</phrase></code>
- explain why we call <code><phrase role="identifier">expires_at</phrase><phrase
- role="special">()</phrase></code> rather than <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/basic_waitable_timer/cancel.html"><code><phrase
- role="identifier">cancel</phrase><phrase role="special">()</phrase></code></ulink>.
- </para>
- <para>
- This <code><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase
- role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase
- role="identifier">asio</phrase><phrase role="special">::</phrase><phrase
- role="identifier">round_robin</phrase></code> implementation is used in
- <ulink url="../../examples/asio/autoecho.cpp"><code><phrase role="identifier">examples</phrase><phrase
- role="special">/</phrase><phrase role="identifier">asio</phrase><phrase role="special">/</phrase><phrase
- role="identifier">autoecho</phrase><phrase role="special">.</phrase><phrase
- role="identifier">cpp</phrase></code></ulink>.
- </para>
- <para>
- It seems possible that you could put together a more elegant Fiber / Asio
- integration. But as noted at the outset: it’s tricky.
- </para>
- </section>
- </section>
- <section id="fiber.speculation">
- <title><anchor id="speculation"/><link linkend="fiber.speculation">Specualtive
- execution</link></title>
- <bridgehead renderas="sect3" id="fiber.speculation.h0">
- <phrase id="fiber.speculation.hardware_transactional_memory"/><link linkend="fiber.speculation.hardware_transactional_memory">Hardware
- transactional memory</link>
- </bridgehead>
- <para>
- With help of hardware transactional memory multiple logical processors execute
- a critical region speculatively, e.g. without explicit synchronization.<sbr/>
- If the transactional execution completes successfully, then all memory operations
- performed within the transactional region are commited without any inter-thread
- serialization.<sbr/> When the optimistic execution fails, the processor aborts
- the transaction and discards all performed modifications.<sbr/> In non-transactional
- code a single lock serializes the access to a critical region. With a transactional
- memory, multiple logical processor start a transaction and update the memory
- (the data) inside the ciritical region. Unless some logical processors try
- to update the same data, the transactions would always succeed.
- </para>
- <bridgehead renderas="sect3" id="fiber.speculation.h1">
- <phrase id="fiber.speculation.intel_transactional_synchronisation_extensions__tsx_"/><link
- linkend="fiber.speculation.intel_transactional_synchronisation_extensions__tsx_">Intel
- Transactional Synchronisation Extensions (TSX)</link>
- </bridgehead>
- <para>
- TSX is Intel's implementation of hardware transactional memory in modern Intel
- processors<footnote id="fiber.speculation.f0">
- <para>
- intel.com: <ulink url="https://software.intel.com/en-us/node/695149">Intel
- Transactional Synchronization Extensions</ulink>
- </para>
- </footnote>.<sbr/> In TSX the hardware keeps track of which cachelines have
- been read from and which have been written to in a transaction. The cache-line
- size (64-byte) and the n-way set associative cache determine the maximum size
- of memory in a transaction. For instance if a transaction modifies 9 cache-lines
- at a processor with a 8-way set associative cache, the transaction will always
- be aborted.
- </para>
- <note>
- <para>
- TXS is enabled if property <code><phrase role="identifier">htm</phrase><phrase
- role="special">=</phrase><phrase role="identifier">tsx</phrase></code> is
- specified at b2 command-line and <code><phrase role="identifier">BOOST_USE_TSX</phrase></code>
- is applied to the compiler.
- </para>
- </note>
- <note>
- <para>
- A TSX-transaction will be aborted if the floating point state is modified
- inside a critical region. As a consequence floating point operations, e.g.
- store/load of floating point related registers during a fiber (context) switch
- are disabled.
- </para>
- </note>
- <important>
- <para>
- TSX can not be used together with MSVC at this time!
- </para>
- </important>
- <para>
- Boost.Fiber uses TSX-enabled spinlocks to protect critical regions (see section
- <link linkend="tuning">Tuning</link>).
- </para>
- </section>
- <section id="fiber.numa">
- <title><anchor id="numa"/><link linkend="fiber.numa">NUMA</link></title>
- <para>
- Modern micro-processors contain integrated memory controllers that are connected
- via channels to the memory. Accessing the memory can be organized in two kinds:<sbr/>
- Uniform Memory Access (UMA) and Non-Uniform Memory Access (NUMA).
- </para>
- <para>
- In contrast to UMA, that provides a centralized pool of memory (and thus does
- not scale after a certain number of processors), a NUMA architecture divides
- the memory into local and remote memory relative to the micro-processor.<sbr/>
- Local memory is directly attached to the processor's integrated memory controller.
- Memory connected to the memory controller of another micro-processor (multi-socket
- systems) is considered as remote memory. If a memory controller access remote
- memory it has to traverse the interconnect<footnote id="fiber.numa.f0">
- <para>
- On x86 the interconnection is implemented by Intel's Quick Path Interconnect
- (QPI) and AMD's HyperTransport.
- </para>
- </footnote> and connect to the remote memory controller.<sbr/> Thus accessing
- remote memory adds additional latency overhead to local memory access. Because
- of the different memory locations, a NUMA-system experiences <emphasis>non-uniform</emphasis>
- memory access time.<sbr/> As a consequence the best performance is achieved
- by keeping the memory access local.
- </para>
- <para>
- <inlinemediaobject><imageobject><imagedata align="center" fileref="../../../../libs/fiber/doc/NUMA.png"></imagedata></imageobject>
- <textobject>
- <phrase>NUMA</phrase>
- </textobject>
- </inlinemediaobject>
- </para>
- <bridgehead renderas="sect3" id="fiber.numa.h0">
- <phrase id="fiber.numa.numa_support_in_boost_fiber"/><link linkend="fiber.numa.numa_support_in_boost_fiber">NUMA
- support in Boost.Fiber</link>
- </bridgehead>
- <para>
- Because only a subset of the NUMA-functionality is exposed by several operating
- systems, Boost.Fiber provides only a minimalistic NUMA API.
- </para>
- <important>
- <para>
- In order to enable NUMA support, b2 property <code><phrase role="identifier">numa</phrase><phrase
- role="special">=</phrase><phrase role="identifier">on</phrase></code> must
- be specified and linked against additional library <code><phrase role="identifier">libboost_fiber_numa</phrase><phrase
- role="special">.</phrase><phrase role="identifier">so</phrase></code>.
- </para>
- </important>
- <important>
- <para>
- MinGW using pthread implementation is not supported on Windows.
- </para>
- </important>
- <table frame="all" id="fiber.numa.supported_functionality_operating_systems">
- <title>Supported functionality/operating systems</title>
- <tgroup cols="7">
- <thead>
- <row>
- <entry>
- </entry>
- <entry>
- <para>
- AIX
- </para>
- </entry>
- <entry>
- <para>
- FreeBSD
- </para>
- </entry>
- <entry>
- <para>
- HP/UX
- </para>
- </entry>
- <entry>
- <para>
- Linux
- </para>
- </entry>
- <entry>
- <para>
- Solaris
- </para>
- </entry>
- <entry>
- <para>
- Windows
- </para>
- </entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- <para>
- pin thread
- </para>
- </entry>
- <entry>
- <para>
- +
- </para>
- </entry>
- <entry>
- <para>
- +
- </para>
- </entry>
- <entry>
- <para>
- +
- </para>
- </entry>
- <entry>
- <para>
- +
- </para>
- </entry>
- <entry>
- <para>
- +
- </para>
- </entry>
- <entry>
- <para>
- +
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- logical CPUs/NUMA nodes
- </para>
- </entry>
- <entry>
- <para>
- +
- </para>
- </entry>
- <entry>
- <para>
- +
- </para>
- </entry>
- <entry>
- <para>
- +
- </para>
- </entry>
- <entry>
- <para>
- +
- </para>
- </entry>
- <entry>
- <para>
- +
- </para>
- </entry>
- <entry>
- <para>
- +<footnote id="fiber.numa.f1">
- <para>
- Windows organizes logical cpus in groups of 64; boost.fiber maps
- {group-id,cpud-id} to a scalar equivalent to cpu ID of Linux (64
- * group ID + cpu ID).
- </para>
- </footnote>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- NUMA node distance
- </para>
- </entry>
- <entry>
- <para>
- -
- </para>
- </entry>
- <entry>
- <para>
- -
- </para>
- </entry>
- <entry>
- <para>
- -
- </para>
- </entry>
- <entry>
- <para>
- +
- </para>
- </entry>
- <entry>
- <para>
- -
- </para>
- </entry>
- <entry>
- <para>
- -
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- tested on
- </para>
- </entry>
- <entry>
- <para>
- AIX 7.2
- </para>
- </entry>
- <entry>
- <para>
- FreeBSD 11
- </para>
- </entry>
- <entry>
- <para>
- -
- </para>
- </entry>
- <entry>
- <para>
- Arch Linux (4.10.13)
- </para>
- </entry>
- <entry>
- <para>
- OpenIndiana HIPSTER
- </para>
- </entry>
- <entry>
- <para>
- Windows 10
- </para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- <para>
- In order to keep the memory access local as possible, the NUMA topology must
- be evaluated.
- </para>
- <programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase role="identifier">node</phrase> <phrase role="special">></phrase> <phrase role="identifier">topo</phrase> <phrase role="special">=</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase role="identifier">topology</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">auto</phrase> <phrase role="identifier">n</phrase> <phrase role="special">:</phrase> <phrase role="identifier">topo</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"node: "</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">n</phrase><phrase role="special">.</phrase><phrase role="identifier">id</phrase> <phrase role="special"><<</phrase> <phrase role="string">" | "</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"cpus: "</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">auto</phrase> <phrase role="identifier">cpu_id</phrase> <phrase role="special">:</phrase> <phrase role="identifier">n</phrase><phrase role="special">.</phrase><phrase role="identifier">logical_cpus</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">cpu_id</phrase> <phrase role="special"><<</phrase> <phrase role="string">" "</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"| distance: "</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">auto</phrase> <phrase role="identifier">d</phrase> <phrase role="special">:</phrase> <phrase role="identifier">n</phrase><phrase role="special">.</phrase><phrase role="identifier">distance</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">d</phrase> <phrase role="special"><<</phrase> <phrase role="string">" "</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"done"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">output</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">node</phrase><phrase role="special">:</phrase> <phrase role="number">0</phrase> <phrase role="special">|</phrase> <phrase role="identifier">cpus</phrase><phrase role="special">:</phrase> <phrase role="number">0</phrase> <phrase role="number">1</phrase> <phrase role="number">2</phrase> <phrase role="number">3</phrase> <phrase role="number">4</phrase> <phrase role="number">5</phrase> <phrase role="number">6</phrase> <phrase role="number">7</phrase> <phrase role="number">16</phrase> <phrase role="number">17</phrase> <phrase role="number">18</phrase> <phrase role="number">19</phrase> <phrase role="number">20</phrase> <phrase role="number">21</phrase> <phrase role="number">22</phrase> <phrase role="number">23</phrase> <phrase role="special">|</phrase> <phrase role="identifier">distance</phrase><phrase role="special">:</phrase> <phrase role="number">10</phrase> <phrase role="number">21</phrase>
- <phrase role="identifier">node</phrase><phrase role="special">:</phrase> <phrase role="number">1</phrase> <phrase role="special">|</phrase> <phrase role="identifier">cpus</phrase><phrase role="special">:</phrase> <phrase role="number">8</phrase> <phrase role="number">9</phrase> <phrase role="number">10</phrase> <phrase role="number">11</phrase> <phrase role="number">12</phrase> <phrase role="number">13</phrase> <phrase role="number">14</phrase> <phrase role="number">15</phrase> <phrase role="number">24</phrase> <phrase role="number">25</phrase> <phrase role="number">26</phrase> <phrase role="number">27</phrase> <phrase role="number">28</phrase> <phrase role="number">29</phrase> <phrase role="number">30</phrase> <phrase role="number">31</phrase> <phrase role="special">|</phrase> <phrase role="identifier">distance</phrase><phrase role="special">:</phrase> <phrase role="number">21</phrase> <phrase role="number">10</phrase>
- <phrase role="identifier">done</phrase>
- </programlisting>
- <para>
- The example shows that the systems consits out of 2 NUMA-nodes, to each NUMA-node
- belong 16 logical cpus. The distance measures the costs to access the memory
- of another NUMA-node. A NUMA-node has always a distance <code><phrase role="number">10</phrase></code>
- to itself (lowest possible value).<sbr/> The position in the array corresponds
- with the NUMA-node ID.
- </para>
- <para>
- Some work-loads benefit from pinning threads to a logical cpus. For instance
- scheduling algorithm <link linkend="class_numa_work_stealing"><code>numa::work_stealing</code></link> pins the thread
- that runs the fiber scheduler to a logical cpu. This prevents the operating
- system scheduler to move the thread to another logical cpu that might run other
- fiber scheduler(s) or migrating the thread to a logical cpu part of another
- NUMA-node.
- </para>
- <programlisting><phrase role="keyword">void</phrase> <phrase role="identifier">thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">cpu_id</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">node_id</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase role="identifier">node</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">topo</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// thread registers itself at work-stealing scheduler</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">algo</phrase><phrase role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase role="identifier">work_stealing</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">cpu_id</phrase><phrase role="special">,</phrase> <phrase role="identifier">node_id</phrase><phrase role="special">,</phrase> <phrase role="identifier">topo</phrase><phrase role="special">);</phrase>
- <phrase role="special">...</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// evaluate the NUMA topology</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase role="identifier">node</phrase> <phrase role="special">></phrase> <phrase role="identifier">topo</phrase> <phrase role="special">=</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase role="identifier">topology</phrase><phrase role="special">();</phrase>
- <phrase role="comment">// start-thread runs on NUMA-node `0`</phrase>
- <phrase role="keyword">auto</phrase> <phrase role="identifier">node</phrase> <phrase role="special">=</phrase> <phrase role="identifier">topo</phrase><phrase role="special">[</phrase><phrase role="number">0</phrase><phrase role="special">];</phrase>
- <phrase role="comment">// start-thread is pinnded to first cpu ID in the list of logical cpus of NUMA-node `0`</phrase>
- <phrase role="keyword">auto</phrase> <phrase role="identifier">start_cpu_id</phrase> <phrase role="special">=</phrase> <phrase role="special">*</phrase> <phrase role="identifier">node</phrase><phrase role="special">.</phrase><phrase role="identifier">logical_cpus</phrase><phrase role="special">.</phrase><phrase role="identifier">begin</phrase><phrase role="special">();</phrase>
- <phrase role="comment">// start worker-threads first</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase> <phrase role="special">></phrase> <phrase role="identifier">threads</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">auto</phrase> <phrase role="special">&</phrase> <phrase role="identifier">node</phrase> <phrase role="special">:</phrase> <phrase role="identifier">topo</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">cpu_id</phrase> <phrase role="special">:</phrase> <phrase role="identifier">node</phrase><phrase role="special">.</phrase><phrase role="identifier">logical_cpus</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// exclude start-thread</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">start_cpu_id</phrase> <phrase role="special">!=</phrase> <phrase role="identifier">cpu_id</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// spawn thread</phrase>
- <phrase role="identifier">threads</phrase><phrase role="special">.</phrase><phrase role="identifier">emplace_back</phrase><phrase role="special">(</phrase> <phrase role="identifier">thread</phrase><phrase role="special">,</phrase> <phrase role="identifier">cpu_id</phrase><phrase role="special">,</phrase> <phrase role="identifier">node</phrase><phrase role="special">.</phrase><phrase role="identifier">id</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cref</phrase><phrase role="special">(</phrase> <phrase role="identifier">topo</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// start-thread registers itself on work-stealing scheduler</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">algo</phrase><phrase role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase role="identifier">work_stealing</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">start_cpu_id</phrase><phrase role="special">,</phrase> <phrase role="identifier">node</phrase><phrase role="special">.</phrase><phrase role="identifier">id</phrase><phrase role="special">,</phrase> <phrase role="identifier">topo</phrase><phrase role="special">);</phrase>
- <phrase role="special">...</phrase>
- </programlisting>
- <para>
- The example evaluates the NUMA topology with <code><phrase role="identifier">boost</phrase><phrase
- role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase
- role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase
- role="identifier">topology</phrase><phrase role="special">()</phrase></code>
- and spawns for each logical cpu a thread. Each spawned thread installs the
- NUMA-aware work-stealing scheduler. The scheduler pins the thread to the logical
- cpu that was specified at construction.<sbr/> If the local queue of one thread
- runs out of ready fibers, the thread tries to steal a ready fiber from another
- thread running at logical cpu that belong to the same NUMA-node (local memory
- access). If no fiber could be stolen, the thread tries to steal fibers from
- logical cpus part of other NUMA-nodes (remote memory access).
- </para>
- <bridgehead renderas="sect3" id="fiber.numa.h1">
- <phrase id="fiber.numa.synopsis"/><link linkend="fiber.numa.synopsis">Synopsis</link>
- </bridgehead>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">numa</phrase><phrase role="special">/</phrase><phrase role="identifier">pin_thread</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">numa</phrase><phrase role="special">/</phrase><phrase role="identifier">topology</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">numa</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">struct</phrase> <phrase role="identifier">node</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">id</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">set</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">logical_cpus</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">distance</phrase><phrase role="special">;</phrase>
- <phrase role="special">};</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special"><(</phrase> <phrase role="identifier">node</phrase> <phrase role="keyword">const</phrase><phrase role="special">&,</phrase> <phrase role="identifier">node</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">node</phrase> <phrase role="special">></phrase> <phrase role="identifier">topology</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">pin_thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">pin_thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">::</phrase><phrase role="identifier">native_handle_type</phrase><phrase role="special">);</phrase>
- <phrase role="special">}}}</phrase>
- <phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">numa</phrase><phrase role="special">/</phrase><phrase role="identifier">algo</phrase><phrase role="special">/</phrase><phrase role="identifier">work_stealing</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">numa</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">algo</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">work_stealing</phrase><phrase role="special">;</phrase>
- <phrase role="special">}}}</phrase>
- </programlisting>
- <para>
- <bridgehead renderas="sect4" id="class_numa_node_bridgehead">
- <phrase id="class_numa_node"/>
- <link linkend="class_numa_node">Class <code>numa::node</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">numa</phrase><phrase role="special">/</phrase><phrase role="identifier">topology</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">numa</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">struct</phrase> <phrase role="identifier">node</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">id</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">set</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">logical_cpus</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">distance</phrase><phrase role="special">;</phrase>
- <phrase role="special">};</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special"><(</phrase> <phrase role="identifier">node</phrase> <phrase role="keyword">const</phrase><phrase role="special">&,</phrase> <phrase role="identifier">node</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="special">}}}</phrase>
- </programlisting>
- <para>
- <bridgehead renderas="sect4" id="numa_node_id_bridgehead">
- <phrase id="numa_node_id"/>
- <link linkend="numa_node_id">Data member <code>id</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">id</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- ID of the NUMA-node
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="numa_node_logical_cpus_bridgehead">
- <phrase id="numa_node_logical_cpus"/>
- <link linkend="numa_node_logical_cpus">Data
- member <code>logical_cpus</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">set</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">logical_cpus</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- set of logical cpu IDs belonging to the NUMA-node
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="numa_node_distance_bridgehead">
- <phrase id="numa_node_distance"/>
- <link linkend="numa_node_distance">Data member
- <code>distance</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">distance</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- The distance between NUMA-nodes describe the cots of accessing the remote
- memory.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- A NUMA-node has a distance of <code><phrase role="number">10</phrase></code>
- to itself, remote NUMA-nodes have a distance > <code><phrase role="number">10</phrase></code>.
- The index in the array corresponds to the ID <code><phrase role="identifier">id</phrase></code>
- of the NUMA-node. At the moment only Linux returns the correct distances,
- for all other operating systems remote NUMA-nodes get a default value
- of <code><phrase role="number">20</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="numa_node_operator_less_bridgehead">
- <phrase id="numa_node_operator_less"/>
- <link linkend="numa_node_operator_less">Member
- function <code>operator<</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">bool</phrase> <phrase role="keyword">operator</phrase><phrase role="special"><(</phrase> <phrase role="identifier">node</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">lhs</phrase><phrase role="special">,</phrase> <phrase role="identifier">node</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">rhs</phrase><phrase role="special">)</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if <code><phrase role="identifier">lhs</phrase>
- <phrase role="special">!=</phrase> <phrase role="identifier">rhs</phrase></code>
- is true and the implementation-defined total order of <code><phrase role="identifier">node</phrase><phrase
- role="special">::</phrase><phrase role="identifier">id</phrase></code>
- values places <code><phrase role="identifier">lhs</phrase></code> before
- <code><phrase role="identifier">rhs</phrase></code>, false otherwise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="numa_topology_bridgehead">
- <phrase id="numa_topology"/>
- <link linkend="numa_topology">Non-member function <code>numa::topology()</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">numa</phrase><phrase role="special">/</phrase><phrase role="identifier">topology</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">numa</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">node</phrase> <phrase role="special">></phrase> <phrase role="identifier">topology</phrase><phrase role="special">();</phrase>
- <phrase role="special">}}}</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Evaluates the NUMA topology.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- a vector of NUMA-nodes describing the NUMA architecture of the system
- (each element represents a NUMA-node).
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">system_error</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="numa_pin_thread_bridgehead">
- <phrase id="numa_pin_thread"/>
- <link linkend="numa_pin_thread">Non-member function
- <code>numa::pin_thread()</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">numa</phrase><phrase role="special">/</phrase><phrase role="identifier">pin_thread</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">numa</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">pin_thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">cpu_id</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">pin_thread</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">cpu_id</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">::</phrase><phrase role="identifier">native_handle_type</phrase> <phrase role="identifier">h</phrase><phrase role="special">);</phrase>
- <phrase role="special">}}}</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- First version pins <code><phrase role="keyword">this</phrase> <phrase
- role="identifier">thread</phrase></code> to the logical cpu with ID
- <code><phrase role="identifier">cpu_id</phrase></code>, e.g. the operating
- system scheduler will not migrate the thread to another logical cpu.
- The second variant pins the thread with the native ID <code><phrase role="identifier">h</phrase></code>
- to logical cpu with ID <code><phrase role="identifier">cpu_id</phrase></code>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">system_error</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="class_numa_work_stealing_bridgehead">
- <phrase id="class_numa_work_stealing"/>
- <link linkend="class_numa_work_stealing">Class
- <code>numa::work_stealing</code></link>
- </bridgehead>
- </para>
- <para>
- This class implements <link linkend="class_algorithm"><code>algorithm</code></link>; the thread running this scheduler
- is pinned to the given logical cpu. If the local ready-queue runs out of ready
- fibers, ready fibers are stolen from other schedulers that run on logical cpus
- that belong to the same NUMA-node (local memory access).<sbr/> If no ready
- fibers can be stolen from the local NUMA-node, the algorithm selects schedulers
- running on other NUMA-nodes (remote memory access).<sbr/> The victim scheduler
- (from which a ready fiber is stolen) is selected at random.
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">numa</phrase><phrase role="special">/</phrase><phrase role="identifier">algo</phrase><phrase role="special">/</phrase><phrase role="identifier">work_stealing</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">numa</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">algo</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">class</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">algorithm</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">work_stealing</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">cpu_id</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">node_id</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase role="identifier">node</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">topo</phrase><phrase role="special">,</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">suspend</phrase> <phrase role="special">=</phrase> <phrase role="keyword">false</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">work_stealing</phrase><phrase role="special">(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">work_stealing</phrase><phrase role="special">(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="special">&&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">work_stealing</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">work_stealing</phrase> <phrase role="special">&</phrase> <phrase role="keyword">operator</phrase><phrase role="special">=(</phrase> <phrase role="identifier">work_stealing</phrase> <phrase role="special">&&)</phrase> <phrase role="special">=</phrase> <phrase role="keyword">delete</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- <phrase role="special">};</phrase>
- <phrase role="special">}}}}</phrase>
- </programlisting>
- <bridgehead renderas="sect3" id="fiber.numa.h2">
- <phrase id="fiber.numa.constructor"/><link linkend="fiber.numa.constructor">Constructor</link>
- </bridgehead>
- <programlisting><phrase role="identifier">work_stealing</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">cpu_id</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uint32_t</phrase> <phrase role="identifier">node_id</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">numa</phrase><phrase role="special">::</phrase><phrase role="identifier">node</phrase> <phrase role="special">></phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">topo</phrase><phrase role="special">,</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">suspend</phrase> <phrase role="special">=</phrase> <phrase role="keyword">false</phrase><phrase role="special">);</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Constructs work-stealing scheduling algorithm. The thread is pinned to
- logical cpu with ID <code><phrase role="identifier">cpu_id</phrase></code>.
- If local ready-queue runs out of ready fibers, ready fibers are stolen
- from other schedulers using <code><phrase role="identifier">topology</phrase></code>
- (represents the NUMA-topology of the system).
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- <code><phrase role="identifier">system_error</phrase></code>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- If <code><phrase role="identifier">suspend</phrase></code> is set to
- <code><phrase role="keyword">true</phrase></code>, then the scheduler
- suspends if no ready fiber could be stolen. The scheduler will by woken
- up if a sleeping fiber times out or it was notified from remote (other
- thread or fiber scheduler).
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="numa_work_stealing_awakened_bridgehead">
- <phrase id="numa_work_stealing_awakened"/>
- <link linkend="numa_work_stealing_awakened">Member
- function <code>awakened</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">f</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Enqueues fiber <code><phrase role="identifier">f</phrase></code> onto
- the shared ready queue.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="numa_work_stealing_pick_next_bridgehead">
- <phrase id="numa_work_stealing_pick_next"/>
- <link linkend="numa_work_stealing_pick_next">Member
- function <code>pick_next</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- the fiber at the head of the ready queue, or <code><phrase role="keyword">nullptr</phrase></code>
- if the queue is empty.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Note:</term>
- <listitem>
- <para>
- Placing ready fibers onto the tail of the sahred queue, and returning
- them from the head of that queue, shares the thread between ready fibers
- in round-robin fashion.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="numa_work_stealing_has_ready_fibers_bridgehead">
- <phrase id="numa_work_stealing_has_ready_fibers"/>
- <link linkend="numa_work_stealing_has_ready_fibers">Member
- function <code>has_ready_fibers</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- <code><phrase role="keyword">true</phrase></code> if scheduler has fibers
- ready to run.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="numa_work_stealing_suspend_until_bridgehead">
- <phrase id="numa_work_stealing_suspend_until"/>
- <link linkend="numa_work_stealing_suspend_until">Member
- function <code>suspend_until</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">abs_time</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Informs <code><phrase role="identifier">work_stealing</phrase></code>
- that no ready fiber will be available until time-point <code><phrase
- role="identifier">abs_time</phrase></code>. This implementation blocks
- in <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable/wait_until"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">condition_variable</phrase><phrase role="special">::</phrase><phrase
- role="identifier">wait_until</phrase><phrase role="special">()</phrase></code></ulink>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- <bridgehead renderas="sect4" id="numa_work_stealing_notify_bridgehead">
- <phrase id="numa_work_stealing_notify"/>
- <link linkend="numa_work_stealing_notify">Member
- function <code>notify</code>()</link>
- </bridgehead>
- </para>
- <programlisting><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Wake up a pending call to <link linkend="work_stealing_suspend_until"><code>work_stealing::suspend_until()</code></link>,
- some fibers might be ready. This implementation wakes <code><phrase role="identifier">suspend_until</phrase><phrase
- role="special">()</phrase></code> via <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable/notify_all"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">condition_variable</phrase><phrase role="special">::</phrase><phrase
- role="identifier">notify_all</phrase><phrase role="special">()</phrase></code></ulink>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Throws:</term>
- <listitem>
- <para>
- Nothing.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section id="fiber.gpu_computing">
- <title><link linkend="fiber.gpu_computing">GPU computing</link></title>
- <section id="fiber.gpu_computing.cuda">
- <title><anchor id="cuda"/><link linkend="fiber.gpu_computing.cuda">CUDA</link></title>
- <para>
- <ulink url="http://developer.nvidia.com/cuda-zone/">CUDA (Compute Unified
- Device Architecture)</ulink> is a platform for parallel computing on NVIDIA
- GPUs. The application programming interface of CUDA gives access to GPU's
- instruction set and computation resources (Execution of compute kernels).
- </para>
- <bridgehead renderas="sect4" id="fiber.gpu_computing.cuda.h0">
- <phrase id="fiber.gpu_computing.cuda.synchronization_with_cuda_streams"/><link
- linkend="fiber.gpu_computing.cuda.synchronization_with_cuda_streams">Synchronization
- with CUDA streams</link>
- </bridgehead>
- <para>
- CUDA operation such as compute kernels or memory transfer (between host and
- device) can be grouped/queued by CUDA streams. are executed on the GPUs.
- Boost.Fiber enables a fiber to sleep (suspend) till a CUDA stream has completed
- its operations. This enables applications to run other fibers on the CPU
- without the need to spawn an additional OS-threads. And resume the fiber
- when the CUDA streams has finished.
- </para>
- <programlisting><phrase role="identifier">__global__</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">kernel</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">size</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">a</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">b</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">c</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">idx</phrase> <phrase role="special">=</phrase> <phrase role="identifier">threadIdx</phrase><phrase role="special">.</phrase><phrase role="identifier">x</phrase> <phrase role="special">+</phrase> <phrase role="identifier">blockIdx</phrase><phrase role="special">.</phrase><phrase role="identifier">x</phrase> <phrase role="special">*</phrase> <phrase role="identifier">blockDim</phrase><phrase role="special">.</phrase><phrase role="identifier">x</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">idx</phrase> <phrase role="special"><</phrase> <phrase role="identifier">size</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">idx1</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">idx</phrase> <phrase role="special">+</phrase> <phrase role="number">1</phrase><phrase role="special">)</phrase> <phrase role="special">%</phrase> <phrase role="number">256</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">idx2</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">idx</phrase> <phrase role="special">+</phrase> <phrase role="number">2</phrase><phrase role="special">)</phrase> <phrase role="special">%</phrase> <phrase role="number">256</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">float</phrase> <phrase role="identifier">as</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">a</phrase><phrase role="special">[</phrase><phrase role="identifier">idx</phrase><phrase role="special">]</phrase> <phrase role="special">+</phrase> <phrase role="identifier">a</phrase><phrase role="special">[</phrase><phrase role="identifier">idx1</phrase><phrase role="special">]</phrase> <phrase role="special">+</phrase> <phrase role="identifier">a</phrase><phrase role="special">[</phrase><phrase role="identifier">idx2</phrase><phrase role="special">])</phrase> <phrase role="special">/</phrase> <phrase role="number">3.0f</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">float</phrase> <phrase role="identifier">bs</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">b</phrase><phrase role="special">[</phrase><phrase role="identifier">idx</phrase><phrase role="special">]</phrase> <phrase role="special">+</phrase> <phrase role="identifier">b</phrase><phrase role="special">[</phrase><phrase role="identifier">idx1</phrase><phrase role="special">]</phrase> <phrase role="special">+</phrase> <phrase role="identifier">b</phrase><phrase role="special">[</phrase><phrase role="identifier">idx2</phrase><phrase role="special">])</phrase> <phrase role="special">/</phrase> <phrase role="number">3.0f</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">c</phrase><phrase role="special">[</phrase><phrase role="identifier">idx</phrase><phrase role="special">]</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">as</phrase> <phrase role="special">+</phrase> <phrase role="identifier">bs</phrase><phrase role="special">)</phrase> <phrase role="special">/</phrase> <phrase role="number">2</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f</phrase><phrase role="special">([&</phrase><phrase role="identifier">done</phrase><phrase role="special">]{</phrase>
- <phrase role="identifier">cudaStream_t</phrase> <phrase role="identifier">stream</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">cudaStreamCreate</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">size</phrase> <phrase role="special">=</phrase> <phrase role="number">1024</phrase> <phrase role="special">*</phrase> <phrase role="number">1024</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">full_size</phrase> <phrase role="special">=</phrase> <phrase role="number">20</phrase> <phrase role="special">*</phrase> <phrase role="identifier">size</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">host_a</phrase><phrase role="special">,</phrase> <phrase role="special">*</phrase> <phrase role="identifier">host_b</phrase><phrase role="special">,</phrase> <phrase role="special">*</phrase> <phrase role="identifier">host_c</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">cudaHostAlloc</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">host_a</phrase><phrase role="special">,</phrase> <phrase role="identifier">full_size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">cudaHostAllocDefault</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">cudaHostAlloc</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">host_b</phrase><phrase role="special">,</phrase> <phrase role="identifier">full_size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">cudaHostAllocDefault</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">cudaHostAlloc</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">host_c</phrase><phrase role="special">,</phrase> <phrase role="identifier">full_size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">cudaHostAllocDefault</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">,</phrase> <phrase role="special">*</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">,</phrase> <phrase role="special">*</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">cudaMalloc</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">cudaMalloc</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">cudaMalloc</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">minstd_rand</phrase> <phrase role="identifier">generator</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int_distribution</phrase><phrase role="special"><></phrase> <phrase role="identifier">distribution</phrase><phrase role="special">(</phrase><phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="number">6</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special"><</phrase> <phrase role="identifier">full_size</phrase><phrase role="special">;</phrase> <phrase role="special">++</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">host_a</phrase><phrase role="special">[</phrase><phrase role="identifier">i</phrase><phrase role="special">]</phrase> <phrase role="special">=</phrase> <phrase role="identifier">distribution</phrase><phrase role="special">(</phrase> <phrase role="identifier">generator</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">host_b</phrase><phrase role="special">[</phrase><phrase role="identifier">i</phrase><phrase role="special">]</phrase> <phrase role="special">=</phrase> <phrase role="identifier">distribution</phrase><phrase role="special">(</phrase> <phrase role="identifier">generator</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special"><</phrase> <phrase role="identifier">full_size</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special">+=</phrase> <phrase role="identifier">size</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">cudaMemcpyAsync</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">,</phrase> <phrase role="identifier">host_a</phrase> <phrase role="special">+</phrase> <phrase role="identifier">i</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">cudaMemcpyHostToDevice</phrase><phrase role="special">,</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">cudaMemcpyAsync</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">,</phrase> <phrase role="identifier">host_b</phrase> <phrase role="special">+</phrase> <phrase role="identifier">i</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">cudaMemcpyHostToDevice</phrase><phrase role="special">,</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">kernel</phrase><phrase role="special"><<<</phrase> <phrase role="identifier">size</phrase> <phrase role="special">/</phrase> <phrase role="number">256</phrase><phrase role="special">,</phrase> <phrase role="number">256</phrase><phrase role="special">,</phrase> <phrase role="number">0</phrase><phrase role="special">,</phrase> <phrase role="identifier">stream</phrase> <phrase role="special">>>>(</phrase> <phrase role="identifier">size</phrase><phrase role="special">,</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">,</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">,</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">cudaMemcpyAsync</phrase><phrase role="special">(</phrase> <phrase role="identifier">host_c</phrase> <phrase role="special">+</phrase> <phrase role="identifier">i</phrase><phrase role="special">,</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">cudaMemcpyDeviceToHost</phrase><phrase role="special">,</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">auto</phrase> <phrase role="identifier">result</phrase> <phrase role="special">=</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">cuda</phrase><phrase role="special">::</phrase><phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase> <phrase role="comment">// suspend fiber till CUDA stream has finished</phrase>
- <phrase role="identifier">BOOST_ASSERT</phrase><phrase role="special">(</phrase> <phrase role="identifier">stream</phrase> <phrase role="special">==</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special"><</phrase> <phrase role="number">0</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">result</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">BOOST_ASSERT</phrase><phrase role="special">(</phrase> <phrase role="identifier">cudaSuccess</phrase> <phrase role="special">==</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special"><</phrase> <phrase role="number">1</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">result</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"f1: GPU computation finished"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">cudaFreeHost</phrase><phrase role="special">(</phrase> <phrase role="identifier">host_a</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">cudaFreeHost</phrase><phrase role="special">(</phrase> <phrase role="identifier">host_b</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">cudaFreeHost</phrase><phrase role="special">(</phrase> <phrase role="identifier">host_c</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">cudaFree</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">cudaFree</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">cudaFree</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">cudaStreamDestroy</phrase><phrase role="special">(</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
- <phrase role="special">});</phrase>
- <phrase role="identifier">f</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
- </programlisting>
- <bridgehead renderas="sect4" id="fiber.gpu_computing.cuda.h1">
- <phrase id="fiber.gpu_computing.cuda.synopsis"/><link linkend="fiber.gpu_computing.cuda.synopsis">Synopsis</link>
- </bridgehead>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">cuda</phrase><phrase role="special">/</phrase><phrase role="identifier">waitfor</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">cuda</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special"><</phrase> <phrase role="identifier">cudaStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">cudaError_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">cudaStream_t</phrase> <phrase role="identifier">st</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special"><</phrase> <phrase role="identifier">cudaStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">cudaError_t</phrase> <phrase role="special">></phrase> <phrase role="special">></phrase> <phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">cudaStream_t</phrase> <phrase role="special">...</phrase> <phrase role="identifier">st</phrase><phrase role="special">);</phrase>
- <phrase role="special">}}}</phrase>
- </programlisting>
- <para>
- <bridgehead renderas="sect4" id="cuda_waitfor_bridgehead">
- <phrase id="cuda_waitfor"/>
- <link linkend="cuda_waitfor">Non-member function <code>cuda::waitfor()</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">cuda</phrase><phrase role="special">/</phrase><phrase role="identifier">waitfor</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">cuda</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special"><</phrase> <phrase role="identifier">cudaStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">cudaError_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">cudaStream_t</phrase> <phrase role="identifier">st</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special"><</phrase> <phrase role="identifier">cudaStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">cudaError_t</phrase> <phrase role="special">></phrase> <phrase role="special">></phrase> <phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">cudaStream_t</phrase> <phrase role="special">...</phrase> <phrase role="identifier">st</phrase><phrase role="special">);</phrase>
- <phrase role="special">}}}</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Suspends active fiber till CUDA stream has finished its operations.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- tuple of stream reference and the CUDA stream status
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- <section id="fiber.gpu_computing.hip">
- <title><anchor id="hip"/><link linkend="fiber.gpu_computing.hip">ROCm/HIP</link></title>
- <para>
- <ulink url="http://github.com/ROCm-Developer-Tools/HIP/tree/roc-1.6.0/">HIP</ulink>
- is part of the <ulink url="http://rocm.github.io/">ROC (Radeon Open Compute)</ulink>
- platform for parallel computing on AMD and NVIDIA GPUs. The application programming
- interface of HIP gives access to GPU's instruction set and computation resources
- (Execution of compute kernels).
- </para>
- <bridgehead renderas="sect4" id="fiber.gpu_computing.hip.h0">
- <phrase id="fiber.gpu_computing.hip.synchronization_with_rocm_hip_streams"/><link
- linkend="fiber.gpu_computing.hip.synchronization_with_rocm_hip_streams">Synchronization
- with ROCm/HIP streams</link>
- </bridgehead>
- <para>
- HIP operation such as compute kernels or memory transfer (between host and
- device) can be grouped/queued by HIP streams. are executed on the GPUs. Boost.Fiber
- enables a fiber to sleep (suspend) till a HIP stream has completed its operations.
- This enables applications to run other fibers on the CPU without the need
- to spawn an additional OS-threads. And resume the fiber when the HIP streams
- has finished.
- </para>
- <programlisting><phrase role="identifier">__global__</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">kernel</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">size</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">a</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">b</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">c</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">idx</phrase> <phrase role="special">=</phrase> <phrase role="identifier">threadIdx</phrase><phrase role="special">.</phrase><phrase role="identifier">x</phrase> <phrase role="special">+</phrase> <phrase role="identifier">blockIdx</phrase><phrase role="special">.</phrase><phrase role="identifier">x</phrase> <phrase role="special">*</phrase> <phrase role="identifier">blockDim</phrase><phrase role="special">.</phrase><phrase role="identifier">x</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">idx</phrase> <phrase role="special"><</phrase> <phrase role="identifier">size</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">idx1</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">idx</phrase> <phrase role="special">+</phrase> <phrase role="number">1</phrase><phrase role="special">)</phrase> <phrase role="special">%</phrase> <phrase role="number">256</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">idx2</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">idx</phrase> <phrase role="special">+</phrase> <phrase role="number">2</phrase><phrase role="special">)</phrase> <phrase role="special">%</phrase> <phrase role="number">256</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">float</phrase> <phrase role="identifier">as</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">a</phrase><phrase role="special">[</phrase><phrase role="identifier">idx</phrase><phrase role="special">]</phrase> <phrase role="special">+</phrase> <phrase role="identifier">a</phrase><phrase role="special">[</phrase><phrase role="identifier">idx1</phrase><phrase role="special">]</phrase> <phrase role="special">+</phrase> <phrase role="identifier">a</phrase><phrase role="special">[</phrase><phrase role="identifier">idx2</phrase><phrase role="special">])</phrase> <phrase role="special">/</phrase> <phrase role="number">3.0f</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">float</phrase> <phrase role="identifier">bs</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">b</phrase><phrase role="special">[</phrase><phrase role="identifier">idx</phrase><phrase role="special">]</phrase> <phrase role="special">+</phrase> <phrase role="identifier">b</phrase><phrase role="special">[</phrase><phrase role="identifier">idx1</phrase><phrase role="special">]</phrase> <phrase role="special">+</phrase> <phrase role="identifier">b</phrase><phrase role="special">[</phrase><phrase role="identifier">idx2</phrase><phrase role="special">])</phrase> <phrase role="special">/</phrase> <phrase role="number">3.0f</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">c</phrase><phrase role="special">[</phrase><phrase role="identifier">idx</phrase><phrase role="special">]</phrase> <phrase role="special">=</phrase> <phrase role="special">(</phrase><phrase role="identifier">as</phrase> <phrase role="special">+</phrase> <phrase role="identifier">bs</phrase><phrase role="special">)</phrase> <phrase role="special">/</phrase> <phrase role="number">2</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f</phrase><phrase role="special">([&</phrase><phrase role="identifier">done</phrase><phrase role="special">]{</phrase>
- <phrase role="identifier">hipStream_t</phrase> <phrase role="identifier">stream</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">hipStreamCreate</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">size</phrase> <phrase role="special">=</phrase> <phrase role="number">1024</phrase> <phrase role="special">*</phrase> <phrase role="number">1024</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">full_size</phrase> <phrase role="special">=</phrase> <phrase role="number">20</phrase> <phrase role="special">*</phrase> <phrase role="identifier">size</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">host_a</phrase><phrase role="special">,</phrase> <phrase role="special">*</phrase> <phrase role="identifier">host_b</phrase><phrase role="special">,</phrase> <phrase role="special">*</phrase> <phrase role="identifier">host_c</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">hipHostMalloc</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">host_a</phrase><phrase role="special">,</phrase> <phrase role="identifier">full_size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">hipHostMallocDefault</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">hipHostMalloc</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">host_b</phrase><phrase role="special">,</phrase> <phrase role="identifier">full_size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">hipHostMallocDefault</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">hipHostMalloc</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">host_c</phrase><phrase role="special">,</phrase> <phrase role="identifier">full_size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">hipHostMallocDefault</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">int</phrase> <phrase role="special">*</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">,</phrase> <phrase role="special">*</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">,</phrase> <phrase role="special">*</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">hipMalloc</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">hipMalloc</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">hipMalloc</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">minstd_rand</phrase> <phrase role="identifier">generator</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">uniform_int_distribution</phrase><phrase role="special"><></phrase> <phrase role="identifier">distribution</phrase><phrase role="special">(</phrase><phrase role="number">1</phrase><phrase role="special">,</phrase> <phrase role="number">6</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special"><</phrase> <phrase role="identifier">full_size</phrase><phrase role="special">;</phrase> <phrase role="special">++</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">host_a</phrase><phrase role="special">[</phrase><phrase role="identifier">i</phrase><phrase role="special">]</phrase> <phrase role="special">=</phrase> <phrase role="identifier">distribution</phrase><phrase role="special">(</phrase> <phrase role="identifier">generator</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">host_b</phrase><phrase role="special">[</phrase><phrase role="identifier">i</phrase><phrase role="special">]</phrase> <phrase role="special">=</phrase> <phrase role="identifier">distribution</phrase><phrase role="special">(</phrase> <phrase role="identifier">generator</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">i</phrase> <phrase role="special">=</phrase> <phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special"><</phrase> <phrase role="identifier">full_size</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase> <phrase role="special">+=</phrase> <phrase role="identifier">size</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">hipMemcpyAsync</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">,</phrase> <phrase role="identifier">host_a</phrase> <phrase role="special">+</phrase> <phrase role="identifier">i</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">hipMemcpyHostToDevice</phrase><phrase role="special">,</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">hipMemcpyAsync</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">,</phrase> <phrase role="identifier">host_b</phrase> <phrase role="special">+</phrase> <phrase role="identifier">i</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">hipMemcpyHostToDevice</phrase><phrase role="special">,</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">hipLaunchKernel</phrase><phrase role="special">(</phrase><phrase role="identifier">kernel</phrase><phrase role="special">,</phrase> <phrase role="identifier">dim3</phrase><phrase role="special">(</phrase><phrase role="identifier">size</phrase> <phrase role="special">/</phrase> <phrase role="number">256</phrase><phrase role="special">),</phrase> <phrase role="identifier">dim3</phrase><phrase role="special">(</phrase><phrase role="number">256</phrase><phrase role="special">),</phrase> <phrase role="number">0</phrase><phrase role="special">,</phrase> <phrase role="identifier">stream</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase><phrase role="special">,</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">,</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">,</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">hipMemcpyAsync</phrase><phrase role="special">(</phrase> <phrase role="identifier">host_c</phrase> <phrase role="special">+</phrase> <phrase role="identifier">i</phrase><phrase role="special">,</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">,</phrase> <phrase role="identifier">size</phrase> <phrase role="special">*</phrase> <phrase role="keyword">sizeof</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase><phrase role="special">),</phrase> <phrase role="identifier">hipMemcpyDeviceToHost</phrase><phrase role="special">,</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">auto</phrase> <phrase role="identifier">result</phrase> <phrase role="special">=</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">hip</phrase><phrase role="special">::</phrase><phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase> <phrase role="comment">// suspend fiber till HIP stream has finished</phrase>
- <phrase role="identifier">BOOST_ASSERT</phrase><phrase role="special">(</phrase> <phrase role="identifier">stream</phrase> <phrase role="special">==</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special"><</phrase> <phrase role="number">0</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">result</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">BOOST_ASSERT</phrase><phrase role="special">(</phrase> <phrase role="identifier">hipSuccess</phrase> <phrase role="special">==</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">get</phrase><phrase role="special"><</phrase> <phrase role="number">1</phrase> <phrase role="special">>(</phrase> <phrase role="identifier">result</phrase><phrase role="special">)</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">cout</phrase> <phrase role="special"><<</phrase> <phrase role="string">"f1: GPU computation finished"</phrase> <phrase role="special"><<</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">endl</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">hipHostFree</phrase><phrase role="special">(</phrase> <phrase role="identifier">host_a</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">hipHostFree</phrase><phrase role="special">(</phrase> <phrase role="identifier">host_b</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">hipHostFree</phrase><phrase role="special">(</phrase> <phrase role="identifier">host_c</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">hipFree</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_a</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">hipFree</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_b</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">hipFree</phrase><phrase role="special">(</phrase> <phrase role="identifier">dev_c</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">hipStreamDestroy</phrase><phrase role="special">(</phrase> <phrase role="identifier">stream</phrase><phrase role="special">);</phrase>
- <phrase role="special">});</phrase>
- <phrase role="identifier">f</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
- </programlisting>
- <bridgehead renderas="sect4" id="fiber.gpu_computing.hip.h1">
- <phrase id="fiber.gpu_computing.hip.synopsis"/><link linkend="fiber.gpu_computing.hip.synopsis">Synopsis</link>
- </bridgehead>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">hip</phrase><phrase role="special">/</phrase><phrase role="identifier">waitfor</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">hip</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special"><</phrase> <phrase role="identifier">hipStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">hipError_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">hipStream_t</phrase> <phrase role="identifier">st</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special"><</phrase> <phrase role="identifier">hipStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">hipError_t</phrase> <phrase role="special">></phrase> <phrase role="special">></phrase> <phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">hipStream_t</phrase> <phrase role="special">...</phrase> <phrase role="identifier">st</phrase><phrase role="special">);</phrase>
- <phrase role="special">}}}</phrase>
- </programlisting>
- <para>
- <bridgehead renderas="sect4" id="hip_waitfor_bridgehead">
- <phrase id="hip_waitfor"/>
- <link linkend="hip_waitfor">Non-member function <code>hip::waitfor()</code></link>
- </bridgehead>
- </para>
- <programlisting><phrase role="preprocessor">#include</phrase> <phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">/</phrase><phrase role="identifier">fiber</phrase><phrase role="special">/</phrase><phrase role="identifier">hip</phrase><phrase role="special">/</phrase><phrase role="identifier">waitfor</phrase><phrase role="special">.</phrase><phrase role="identifier">hpp</phrase><phrase role="special">></phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">boost</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">fibers</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">namespace</phrase> <phrase role="identifier">hip</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special"><</phrase> <phrase role="identifier">hipStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">hipError_t</phrase> <phrase role="special">></phrase> <phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">hipStream_t</phrase> <phrase role="identifier">st</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">vector</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">tuple</phrase><phrase role="special"><</phrase> <phrase role="identifier">hipStream_t</phrase><phrase role="special">,</phrase> <phrase role="identifier">hipError_t</phrase> <phrase role="special">></phrase> <phrase role="special">></phrase> <phrase role="identifier">waitfor_all</phrase><phrase role="special">(</phrase> <phrase role="identifier">hipStream_t</phrase> <phrase role="special">...</phrase> <phrase role="identifier">st</phrase><phrase role="special">);</phrase>
- <phrase role="special">}}}</phrase>
- </programlisting>
- <variablelist>
- <title></title>
- <varlistentry>
- <term>Effects:</term>
- <listitem>
- <para>
- Suspends active fiber till HIP stream has finished its operations.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Returns:</term>
- <listitem>
- <para>
- tuple of stream reference and the HIP stream status
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </section>
- </section>
- <section id="fiber.worker">
- <title><anchor id="worker"/><link linkend="fiber.worker">Running with worker
- threads</link></title>
- <bridgehead renderas="sect3" id="fiber.worker.h0">
- <phrase id="fiber.worker.keep_workers_running"/><link linkend="fiber.worker.keep_workers_running">Keep
- workers running</link>
- </bridgehead>
- <para>
- If a worker thread is used but no fiber is created or parts of the framework
- (like <link linkend="this_fiber_yield"><code>this_fiber::yield()</code></link>) are touched, then no fiber scheduler
- is instantiated.
- </para>
- <programlisting><phrase role="keyword">auto</phrase> <phrase role="identifier">worker</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">(</phrase>
- <phrase role="special">[]{</phrase>
- <phrase role="comment">// fiber scheduler not instantiated</phrase>
- <phrase role="special">});</phrase>
- <phrase role="identifier">worker</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
- </programlisting>
- <para>
- If <emphasis>use_scheduling_algorithm<>()</emphasis> is invoked, the
- fiber scheduler is created. If the worker thread simply returns, destroys the
- scheduler and terminates.
- </para>
- <programlisting><phrase role="keyword">auto</phrase> <phrase role="identifier">worker</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">(</phrase>
- <phrase role="special">[]{</phrase>
- <phrase role="comment">// fiber scheduler created</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special"><</phrase><phrase role="identifier">my_fiber_scheduler</phrase><phrase role="special">>();</phrase>
- <phrase role="special">});</phrase>
- <phrase role="identifier">worker</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
- </programlisting>
- <para>
- In order to keep the worker thread running, the fiber associated with the thread
- stack (which is called <quote>main</quote> fiber) is blocked. For instance
- the <quote>main</quote> fiber might wait on a <link linkend="class_condition_variable"><code>condition_variable</code></link>.
- For a gracefully shutdown <link linkend="class_condition_variable"><code>condition_variable</code></link> is signalled
- and the <quote>main</quote> fiber returns. The scheduler gets destructed if
- all fibers of the worker thread have been terminated.
- </para>
- <programlisting><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="identifier">mtx</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">condition_variable_any</phrase> <phrase role="identifier">cv</phrase><phrase role="special">;</phrase>
- <phrase role="keyword">auto</phrase> <phrase role="identifier">worker</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">(</phrase>
- <phrase role="special">[&</phrase><phrase role="identifier">mtx</phrase><phrase role="special">,&</phrase><phrase role="identifier">cv</phrase><phrase role="special">]{</phrase>
- <phrase role="identifier">mtx</phrase><phrase role="special">.</phrase><phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
- <phrase role="comment">// suspend till signalled</phrase>
- <phrase role="identifier">cv</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">(</phrase><phrase role="identifier">mtx</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">mtx</phrase><phrase role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
- <phrase role="special">});</phrase>
- <phrase role="comment">// signal termination</phrase>
- <phrase role="identifier">cv</phrase><phrase role="special">.</phrase><phrase role="identifier">notify_all</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">worker</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
- </programlisting>
- <bridgehead renderas="sect3" id="fiber.worker.h1">
- <phrase id="fiber.worker.processing_tasks"/><link linkend="fiber.worker.processing_tasks">Processing
- tasks</link>
- </bridgehead>
- <para>
- Tasks can be transferred via channels. The worker thread runs a pool of fibers
- that dequeue and executed tasks from the channel. The termination is signalled
- via closing the channel.
- </para>
- <programlisting><phrase role="keyword">using</phrase> <phrase role="identifier">task</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">function</phrase><phrase role="special"><</phrase><phrase role="keyword">void</phrase><phrase role="special">()>;</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">buffered_channel</phrase><phrase role="special"><</phrase><phrase role="identifier">task</phrase><phrase role="special">></phrase> <phrase role="identifier">ch</phrase><phrase role="special">{</phrase><phrase role="number">1024</phrase><phrase role="special">};</phrase>
- <phrase role="keyword">auto</phrase> <phrase role="identifier">worker</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">(</phrase>
- <phrase role="special">[&</phrase><phrase role="identifier">ch</phrase><phrase role="special">]{</phrase>
- <phrase role="comment">// create pool of fibers</phrase>
- <phrase role="keyword">for</phrase> <phrase role="special">(</phrase><phrase role="keyword">int</phrase> <phrase role="identifier">i</phrase><phrase role="special">=</phrase><phrase role="number">0</phrase><phrase role="special">;</phrase> <phrase role="identifier">i</phrase><phrase role="special"><</phrase><phrase role="number">10</phrase><phrase role="special">;</phrase> <phrase role="special">++</phrase><phrase role="identifier">i</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase><phrase role="special">{</phrase>
- <phrase role="special">[&</phrase><phrase role="identifier">ch</phrase><phrase role="special">]{</phrase>
- <phrase role="identifier">task</phrase> <phrase role="identifier">tsk</phrase><phrase role="special">;</phrase>
- <phrase role="comment">// dequeue and process tasks</phrase>
- <phrase role="keyword">while</phrase> <phrase role="special">(</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">channel_op_status</phrase><phrase role="special">::</phrase><phrase role="identifier">closed</phrase><phrase role="special">!=</phrase><phrase role="identifier">ch</phrase><phrase role="special">.</phrase><phrase role="identifier">pop</phrase><phrase role="special">(</phrase><phrase role="identifier">tsk</phrase><phrase role="special">)){</phrase>
- <phrase role="identifier">tsk</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}}.</phrase><phrase role="identifier">detach</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">task</phrase> <phrase role="identifier">tsk</phrase><phrase role="special">;</phrase>
- <phrase role="comment">// dequeue and process tasks</phrase>
- <phrase role="keyword">while</phrase> <phrase role="special">(</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">channel_op_status</phrase><phrase role="special">::</phrase><phrase role="identifier">closed</phrase><phrase role="special">!=</phrase><phrase role="identifier">ch</phrase><phrase role="special">.</phrase><phrase role="identifier">pop</phrase><phrase role="special">(</phrase><phrase role="identifier">tsk</phrase><phrase role="special">)){</phrase>
- <phrase role="identifier">tsk</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">});</phrase>
- <phrase role="comment">// feed channel with tasks</phrase>
- <phrase role="identifier">ch</phrase><phrase role="special">.</phrase><phrase role="identifier">push</phrase><phrase role="special">([]{</phrase> <phrase role="special">...</phrase> <phrase role="special">});</phrase>
- <phrase role="special">...</phrase>
- <phrase role="comment">// signal termination</phrase>
- <phrase role="identifier">ch</phrase><phrase role="special">.</phrase><phrase role="identifier">close</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">worker</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
- </programlisting>
- <para>
- An alternative is to use a work-stealing scheduler. This kind of scheduling
- algorithm a worker thread steals fibers from the ready-queue of other worker
- threads if its own ready-queue is empty.
- </para>
- <note>
- <para>
- Wait till all worker threads have registered the work-stealing scheduling
- algorithm.
- </para>
- </note>
- <programlisting><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="identifier">mtx</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">condition_variable_any</phrase> <phrase role="identifier">cv</phrase><phrase role="special">;</phrase>
- <phrase role="comment">// start wotrker-thread first</phrase>
- <phrase role="keyword">auto</phrase> <phrase role="identifier">worker</phrase> <phrase role="special">=</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">thread</phrase><phrase role="special">(</phrase>
- <phrase role="special">[&</phrase><phrase role="identifier">mtx</phrase><phrase role="special">,&</phrase><phrase role="identifier">cv</phrase><phrase role="special">]{</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">algo</phrase><phrase role="special">::</phrase><phrase role="identifier">work_stealing</phrase><phrase role="special">>(</phrase><phrase role="number">2</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">mtx</phrase><phrase role="special">.</phrase><phrase role="identifier">lock</phrase><phrase role="special">();</phrase>
- <phrase role="comment">// suspend main-fiber from the worker thread</phrase>
- <phrase role="identifier">cv</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">(</phrase><phrase role="identifier">mtx</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">mtx</phrase><phrase role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
- <phrase role="special">});</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special"><</phrase><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">algo</phrase><phrase role="special">::</phrase><phrase role="identifier">work_stealing</phrase><phrase role="special">>(</phrase><phrase role="number">2</phrase><phrase role="special">);</phrase>
- <phrase role="comment">// create fibers with tasks</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">f</phrase><phrase role="special">{[]{</phrase> <phrase role="special">...</phrase> <phrase role="special">}};</phrase>
- <phrase role="special">...</phrase>
- <phrase role="comment">// signal termination</phrase>
- <phrase role="identifier">cv</phrase><phrase role="special">.</phrase><phrase role="identifier">notify_all</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">worker</phrase><phrase role="special">.</phrase><phrase role="identifier">join</phrase><phrase role="special">();</phrase>
- </programlisting>
- <important>
- <para>
- Because the TIB (thread information block on Windows) is not fully described
- in the MSDN, it might be possible that not all required TIB-parts are swapped.
- Using WinFiber implementation might be an alternative (see documentation
- about <ulink url="http://www.boost.org/doc/libs/1_65_1/libs/context/doc/html/context/cc/implementations__fcontext_t__ucontext_t_and_winfiber.html"><emphasis>implementations
- fcontext_t, ucontext_t and WinFiber of boost.context</emphasis></ulink>).
- </para>
- </important>
- </section>
- <section id="fiber.performance">
- <title><link linkend="fiber.performance">Performance</link></title>
- <para>
- Performance measurements were taken using <code><phrase role="identifier">std</phrase><phrase
- role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase
- role="special">::</phrase><phrase role="identifier">highresolution_clock</phrase></code>,
- with overhead corrections. The code was compiled with gcc-6.3.1, using build
- options: variant = release, optimization = speed. Tests were executed on dual
- Intel XEON E5 2620v4 2.2GHz, 16C/32T, 64GB RAM, running Linux (x86_64).
- </para>
- <para>
- Measurements headed 1C/1T were run in a single-threaded process.
- </para>
- <para>
- The <ulink url="https://github.com/atemerev/skynet">microbenchmark <emphasis>syknet</emphasis></ulink>
- from Alexander Temerev was ported and used for performance measurements. At
- the root the test spawns 10 threads-of-execution (ToE), e.g. actor/goroutine/fiber
- etc.. Each spawned ToE spawns additional 10 ToEs ... until <emphasis role="bold">1,000,000</emphasis>
- ToEs are created. ToEs return back their ordinal numbers (0 ... 999,999), which
- are summed on the previous level and sent back upstream, until reaching the
- root. The test was run 10-20 times, producing a range of values for each measurement.
- </para>
- <table frame="all" id="fiber.performance.time_per_actor_erlang_process_goroutine__other_languages___average_over_1_000_000_">
- <title>time per actor/erlang process/goroutine (other languages) (average over
- 1,000,000)</title>
- <tgroup cols="3">
- <thead>
- <row>
- <entry>
- <para>
- Haskell | stack-1.4.0/ghc-8.0.1
- </para>
- </entry>
- <entry>
- <para>
- Go | go1.8.1
- </para>
- </entry>
- <entry>
- <para>
- Erlang | erts-8.3
- </para>
- </entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- <para>
- 0.05 µs - 0.06 µs
- </para>
- </entry>
- <entry>
- <para>
- 0.42 µs - 0.49 µs
- </para>
- </entry>
- <entry>
- <para>
- 0.63 µs - 0.73 µs
- </para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- <para>
- Pthreads are created with a stack size of 8kB while <code><phrase role="identifier">std</phrase><phrase
- role="special">::</phrase><phrase role="identifier">thread</phrase></code>'s
- use the system default (1MB - 2MB). The microbenchmark could <emphasis role="bold">not</emphasis>
- be <emphasis role="bold">run</emphasis> with 1,000,000 threads because of
- <emphasis role="bold">resource exhaustion</emphasis> (pthread and std::thread).
- Instead the test runs only at <emphasis role="bold">10,000</emphasis> threads.
- </para>
- <table frame="all" id="fiber.performance.time_per_thread__average_over_10_000___unable_to_spawn_1_000_000_threads_">
- <title>time per thread (average over 10,000 - unable to spawn 1,000,000 threads)</title>
- <tgroup cols="3">
- <thead>
- <row>
- <entry>
- <para>
- pthread
- </para>
- </entry>
- <entry>
- <para>
- <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">thread</phrase></code>
- </para>
- </entry>
- <entry>
- <para>
- <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">async</phrase></code>
- </para>
- </entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- <para>
- 54 µs - 73 µs
- </para>
- </entry>
- <entry>
- <para>
- 52 µs - 73 µs
- </para>
- </entry>
- <entry>
- <para>
- 106 µs - 122 µs
- </para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- <para>
- The test utilizes 16 cores with Symmetric MultiThreading enabled (32 logical
- CPUs). The fiber stacks are allocated by <link linkend="class_fixedsize_stack"><code>fixedsize_stack</code></link>.
- </para>
- <para>
- As the benchmark shows, the memory allocation algorithm is significant for
- performance in a multithreaded environment. The tests use glibc’s memory allocation
- algorithm (based on ptmalloc2) as well as Google’s <ulink url="http://goog-perftools.sourceforge.net/doc/tcmalloc.html">TCmalloc</ulink>
- (via linkflags="-ltcmalloc").<footnote id="fiber.performance.f0">
- <para>
- Tais B. Ferreira, Rivalino Matias, Autran Macedo, Lucio B. Araujo <quote>An
- Experimental Study on Memory Allocators in Multicore and Multithreaded Applications</quote>,
- PDCAT ’11 Proceedings of the 2011 12th International Conference on Parallel
- and Distributed Computing, Applications and Technologies, pages 92-98
- </para>
- </footnote>
- </para>
- <para>
- In the <link linkend="class_work_stealing"><code>work_stealing</code></link> scheduling algorithm, each thread has
- its own local queue. Fibers that are ready to run are pushed to and popped
- from the local queue. If the queue runs out of ready fibers, fibers are stolen
- from the local queues of other participating threads.
- </para>
- <table frame="all" id="fiber.performance.time_per_fiber__average_over_1_000_000_">
- <title>time per fiber (average over 1.000.000)</title>
- <tgroup cols="2">
- <thead>
- <row>
- <entry>
- <para>
- fiber (16C/32T, work stealing, tcmalloc)
- </para>
- </entry>
- <entry>
- <para>
- fiber (1C/1T, round robin, tcmalloc)
- </para>
- </entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- <para>
- 0.05 µs - 0.09 µs
- </para>
- </entry>
- <entry>
- <para>
- 1.69 µs - 1.79 µs
- </para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </section>
- <section id="fiber.tuning">
- <title><anchor id="tuning"/><link linkend="fiber.tuning">Tuning</link></title>
- <bridgehead renderas="sect3" id="fiber.tuning.h0">
- <phrase id="fiber.tuning.disable_synchronization"/><link linkend="fiber.tuning.disable_synchronization">Disable
- synchronization</link>
- </bridgehead>
- <para>
- With <link linkend="cross_thread_sync"><code><phrase role="identifier">BOOST_FIBERS_NO_ATOMICS</phrase></code></link>
- defined at the compiler’s command line, synchronization between fibers (in different
- threads) is disabled. This is acceptable if the application is single threaded
- and/or fibers are not synchronized between threads.
- </para>
- <bridgehead renderas="sect3" id="fiber.tuning.h1">
- <phrase id="fiber.tuning.memory_allocation"/><link linkend="fiber.tuning.memory_allocation">Memory
- allocation</link>
- </bridgehead>
- <para>
- Memory allocation algorithm is significant for performance in a multithreaded
- environment, especially for <emphasis role="bold">Boost.Fiber</emphasis> where
- fiber stacks are allocated on the heap. The default user-level memory allocator
- (UMA) of glibc is ptmalloc2 but it can be replaced by another UMA that fit
- better for the concret work-load For instance Google’s <ulink url="http://goog-perftools.sourceforge.net/doc/tcmalloc.html">TCmalloc</ulink>
- enables a better performance at the <emphasis>skynet</emphasis> microbenchmark
- than glibc’s default memory allocator.
- </para>
- <bridgehead renderas="sect3" id="fiber.tuning.h2">
- <phrase id="fiber.tuning.scheduling_strategies"/><link linkend="fiber.tuning.scheduling_strategies">Scheduling
- strategies</link>
- </bridgehead>
- <para>
- The fibers in a thread are coordinated by a fiber manager. Fibers trade control
- cooperatively, rather than preemptively. Depending on the work-load several
- strategies of scheduling the fibers are possible <footnote id="fiber.tuning.f0">
- <para>
- 1024cores.net: <ulink url="http://www.1024cores.net/home/scalable-architecture/task-scheduling-strategies">Task
- Scheduling Strategies</ulink>
- </para>
- </footnote> that can be implmented on behalf of <link linkend="class_algorithm"><code>algorithm</code></link>.
- </para>
- <itemizedlist>
- <listitem>
- <simpara>
- work-stealing: ready fibers are hold in a local queue, when the fiber-scheduler's
- local queue runs out of ready fibers, it randomly selects another fiber-scheduler
- and tries to steal a ready fiber from the victim (implemented in <link linkend="class_work_stealing"><code>work_stealing</code></link> and
- <link linkend="class_numa_work_stealing"><code>numa::work_stealing</code></link>)
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- work-requesting: ready fibers are hold in a local queue, when the fiber-scheduler's
- local queue runs out of ready fibers, it randomly selects another fiber-scheduler
- and requests for a ready fibers, the victim fiber-scheduler sends a ready-fiber
- back
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- work-sharing: ready fibers are hold in a global queue, fiber-scheduler
- concurrently push and pop ready fibers to/from the global queue (implemented
- in <link linkend="class_shared_work"><code>shared_work</code></link>)
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- work-distribution: fibers that became ready are proactivly distributed
- to idle fiber-schedulers or fiber-schedulers with low load
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- work-balancing: a dedicated (helper) fiber-scheduler periodically collects
- informations about all fiber-scheduler running in other threads and re-distributes
- ready fibers among them
- </simpara>
- </listitem>
- </itemizedlist>
- <bridgehead renderas="sect3" id="fiber.tuning.h3">
- <phrase id="fiber.tuning.ttas_locks"/><link linkend="fiber.tuning.ttas_locks">TTAS
- locks</link>
- </bridgehead>
- <para>
- Boost.Fiber uses internally spinlocks to protect critical regions if fibers
- running on different threads interact. Spinlocks are implemented as TTAS (test-test-and-set)
- locks, i.e. the spinlock tests the lock before calling an atomic exchange.
- This strategy helps to reduce the cache line invalidations triggered by acquiring/releasing
- the lock.
- </para>
- <bridgehead renderas="sect3" id="fiber.tuning.h4">
- <phrase id="fiber.tuning.spin_wait_loop"/><link linkend="fiber.tuning.spin_wait_loop">Spin-wait
- loop</link>
- </bridgehead>
- <para>
- A lock is considered under contention, if a thread repeatedly fails to acquire
- the lock because some other thread was faster. Waiting for a short time lets
- other threads finish before trying to enter the critical section again. While
- busy waiting on the lock, relaxing the CPU (via pause/yield mnemonic) gives
- the CPU a hint that the code is in a spin-wait loop.
- </para>
- <itemizedlist>
- <listitem>
- <simpara>
- prevents expensive pipeline flushes (speculatively executed load and compare
- instructions are not pushed to pipeline)
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- another hardware thread (simultaneous multithreading) can get time slice
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- it does delay a few CPU cycles, but this is necessary to prevent starvation
- </simpara>
- </listitem>
- </itemizedlist>
- <para>
- It is obvious that this strategy is useless on single core systems because
- the lock can only released if the thread gives up its time slice in order to
- let other threads run. The macro BOOST_FIBERS_SPIN_SINGLE_CORE replaces the
- CPU hints (pause/yield mnemonic) by informing the operating system (via <code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">this_thread_yield</phrase><phrase
- role="special">()</phrase></code>) that the thread gives up its time slice
- and the operating system switches to another thread.
- </para>
- <bridgehead renderas="sect3" id="fiber.tuning.h5">
- <phrase id="fiber.tuning.exponential_back_off"/><link linkend="fiber.tuning.exponential_back_off">Exponential
- back-off</link>
- </bridgehead>
- <para>
- The macro BOOST_FIBERS_RETRY_THRESHOLD determines how many times the CPU iterates
- in the spin-wait loop before yielding the thread or blocking in futex-wait.
- The spinlock tracks how many times the thread failed to acquire the lock. The
- higher the contention, the longer the thread should back-off. A <quote>Binary
- Exponential Backoff</quote> algorithm together with a randomized contention
- window is utilized for this purpose. BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD
- determines the upper limit of the contention window (expressed as the exponent
- for basis of two).
- </para>
- <bridgehead renderas="sect3" id="fiber.tuning.h6">
- <phrase id="fiber.tuning.speculative_execution__hardware_transactional_memory_"/><link
- linkend="fiber.tuning.speculative_execution__hardware_transactional_memory_">Speculative
- execution (hardware transactional memory)</link>
- </bridgehead>
- <para>
- Boost.Fiber uses spinlocks to protect critical regions that can be used together
- with transactional memory (see section <link linkend="speculation">Speculative
- execution</link>).
- </para>
- <note>
- <para>
- TXS is enabled if property <code><phrase role="identifier">htm</phrase><phrase
- role="special">=</phrase><phrase role="identifier">tsx</phrase></code> is
- specified at b2 command-line and <code><phrase role="identifier">BOOST_USE_TSX</phrase></code>
- is applied to the compiler.
- </para>
- </note>
- <note>
- <para>
- A TSX-transaction will be aborted if the floating point state is modified
- inside a critical region. As a consequence floating point operations, e.g.
- tore/load of floating point related registers during a fiber (context) switch
- are disabled.
- </para>
- </note>
- <bridgehead renderas="sect3" id="fiber.tuning.h7">
- <phrase id="fiber.tuning.numa_systems"/><link linkend="fiber.tuning.numa_systems">NUMA
- systems</link>
- </bridgehead>
- <para>
- Modern multi-socket systems are usually designed as <link linkend="numa">NUMA
- systems</link>. A suitable fiber scheduler like <link linkend="class_numa_work_stealing"><code>numa::work_stealing</code></link> reduces
- remote memory access (latence).
- </para>
- <bridgehead renderas="sect3" id="fiber.tuning.h8">
- <phrase id="fiber.tuning.parameters"/><link linkend="fiber.tuning.parameters">Parameters</link>
- </bridgehead>
- <table frame="all" id="fiber.tuning.parameters_that_migh_be_defiend_at_compiler_s_command_line">
- <title>Parameters that migh be defiend at compiler's command line</title>
- <tgroup cols="3">
- <thead>
- <row>
- <entry>
- <para>
- Parameter
- </para>
- </entry>
- <entry>
- <para>
- Default value
- </para>
- </entry>
- <entry>
- <para>
- Effect on Boost.Fiber
- </para>
- </entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- <para>
- BOOST_FIBERS_NO_ATOMICS
- </para>
- </entry>
- <entry>
- <para>
- -
- </para>
- </entry>
- <entry>
- <para>
- no multithreading support, all atomics removed, no synchronization
- between fibers running in different threads
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- BOOST_FIBERS_SPINLOCK_STD_MUTEX
- </para>
- </entry>
- <entry>
- <para>
- -
- </para>
- </entry>
- <entry>
- <para>
- <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">mutex</phrase></code> used inside spinlock
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- BOOST_FIBERS_SPINLOCK_TTAS
- </para>
- </entry>
- <entry>
- <para>
- +
- </para>
- </entry>
- <entry>
- <para>
- spinlock with test-test-and-swap on shared variable
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE
- </para>
- </entry>
- <entry>
- <para>
- -
- </para>
- </entry>
- <entry>
- <para>
- spinlock with test-test-and-swap on shared variable, adaptive retries
- while busy waiting
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- BOOST_FIBERS_SPINLOCK_TTAS_FUTEX
- </para>
- </entry>
- <entry>
- <para>
- -
- </para>
- </entry>
- <entry>
- <para>
- spinlock with test-test-and-swap on shared variable, suspend on futex
- after certain number of retries
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE_FUTEX
- </para>
- </entry>
- <entry>
- <para>
- -
- </para>
- </entry>
- <entry>
- <para>
- spinlock with test-test-and-swap on shared variable, while busy waiting
- adaptive retries, suspend on futex certain amount of retries
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- BOOST_FIBERS_SPINLOCK_TTAS + BOOST_USE_TSX
- </para>
- </entry>
- <entry>
- <para>
- -
- </para>
- </entry>
- <entry>
- <para>
- spinlock with test-test-and-swap and speculative execution (Intel
- TSX required)
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE + BOOST_USE_TSX
- </para>
- </entry>
- <entry>
- <para>
- -
- </para>
- </entry>
- <entry>
- <para>
- spinlock with test-test-and-swap on shared variable, adaptive retries
- while busy waiting and speculative execution (Intel TSX required)
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- BOOST_FIBERS_SPINLOCK_TTAS_FUTEX + BOOST_USE_TSX
- </para>
- </entry>
- <entry>
- <para>
- -
- </para>
- </entry>
- <entry>
- <para>
- spinlock with test-test-and-swap on shared variable, suspend on futex
- after certain number of retries and speculative execution (Intel
- TSX required)
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE_FUTEX + BOOST_USE_TSX
- </para>
- </entry>
- <entry>
- <para>
- -
- </para>
- </entry>
- <entry>
- <para>
- spinlock with test-test-and-swap on shared variable, while busy waiting
- adaptive retries, suspend on futex certain amount of retries and
- speculative execution (Intel TSX required)
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- BOOST_FIBERS_SPIN_SINGLE_CORE
- </para>
- </entry>
- <entry>
- <para>
- -
- </para>
- </entry>
- <entry>
- <para>
- on single core machines with multiple threads, yield thread (<code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">this_thread</phrase><phrase role="special">::</phrase><phrase
- role="identifier">yield</phrase><phrase role="special">()</phrase></code>)
- after collisions
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- BOOST_FIBERS_RETRY_THRESHOLD
- </para>
- </entry>
- <entry>
- <para>
- 64
- </para>
- </entry>
- <entry>
- <para>
- max number of retries while busy spinning, the use fallback
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD
- </para>
- </entry>
- <entry>
- <para>
- 16
- </para>
- </entry>
- <entry>
- <para>
- max size of collisions window, expressed as exponent for the basis
- of two
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- BOOST_FIBERS_SPIN_BEFORE_SLEEP0
- </para>
- </entry>
- <entry>
- <para>
- 32
- </para>
- </entry>
- <entry>
- <para>
- max number of retries that relax the processor before the thread
- sleeps for 0s
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- BOOST_FIBERS_SPIN_BEFORE_YIELD
- </para>
- </entry>
- <entry>
- <para>
- 64
- </para>
- </entry>
- <entry>
- <para>
- max number of retries where the thread sleeps for 0s before yield
- thread (<code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">this_thread</phrase><phrase role="special">::</phrase><phrase
- role="identifier">yield</phrase><phrase role="special">()</phrase></code>)
- </para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </section>
- <section id="fiber.custom">
- <title><anchor id="custom"/><link linkend="fiber.custom">Customization</link></title>
- <bridgehead renderas="sect3" id="fiber.custom.h0">
- <phrase id="fiber.custom.overview"/><link linkend="fiber.custom.overview">Overview</link>
- </bridgehead>
- <para>
- As noted in the <link linkend="scheduling">Scheduling</link> section, by default
- <emphasis role="bold">Boost.Fiber</emphasis> uses its own <link linkend="class_round_robin"><code>round_robin</code></link> scheduler
- for each thread. To control the way <emphasis role="bold">Boost.Fiber</emphasis>
- schedules ready fibers on a particular thread, in general you must follow several
- steps. This section discusses those steps, whereas <link linkend="scheduling">Scheduling</link>
- serves as a reference for the classes involved.
- </para>
- <para>
- The library's fiber manager keeps track of suspended (blocked) fibers. Only
- when a fiber becomes ready to run is it passed to the scheduler. Of course,
- if there are fewer than two ready fibers, the scheduler's job is trivial. Only
- when there are two or more ready fibers does the particular scheduler implementation
- start to influence the overall sequence of fiber execution.
- </para>
- <para>
- In this section we illustrate a simple custom scheduler that honors an integer
- fiber priority. We will implement it such that a fiber with higher priority
- is preferred over a fiber with lower priority. Any fibers with equal priority
- values are serviced on a round-robin basis.
- </para>
- <para>
- The full source code for the examples below is found in <ulink url="../../examples/priority.cpp">priority.cpp</ulink>.
- </para>
- <bridgehead renderas="sect3" id="fiber.custom.h1">
- <phrase id="fiber.custom.custom_property_class"/><link linkend="fiber.custom.custom_property_class">Custom
- Property Class</link>
- </bridgehead>
- <para>
- The first essential point is that we must associate an integer priority with
- each fiber.<footnote id="fiber.custom.f0">
- <para>
- A previous version of the Fiber library implicitly tracked an int priority
- for each fiber, even though the default scheduler ignored it. This has been
- dropped, since the library now supports arbitrary scheduler-specific fiber
- properties.
- </para>
- </footnote>
- </para>
- <para>
- One might suggest deriving a custom <link linkend="class_fiber"><code>fiber</code></link> subclass to store such
- properties. There are a couple of reasons for the present mechanism.
- </para>
- <orderedlist>
- <listitem>
- <simpara>
- <emphasis role="bold">Boost.Fiber</emphasis> provides a number of different
- ways to launch a fiber. (Consider <link linkend="fibers_async"><code>fibers::async()</code></link>.) Higher-level
- libraries might introduce additional such wrapper functions. A custom scheduler
- must associate its custom properties with <emphasis>every</emphasis> fiber
- in the thread, not only the ones explicitly launched by instantiating a
- custom <code><phrase role="identifier">fiber</phrase></code> subclass.
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- Consider a large existing program that launches fibers in many different
- places in the code. We discover a need to introduce a custom scheduler
- for a particular thread. If supporting that scheduler's custom properties
- required a particular <code><phrase role="identifier">fiber</phrase></code>
- subclass, we would have to hunt down and modify every place that launches
- a fiber on that thread.
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- The <link linkend="class_fiber"><code>fiber</code></link> class is actually just a handle to internal <link linkend="class_context"><code>context</code></link> data.
- A subclass of <code><phrase role="identifier">fiber</phrase></code> would
- not add data to <code><phrase role="identifier">context</phrase></code>.
- </simpara>
- </listitem>
- </orderedlist>
- <para>
- The present mechanism allows you to <quote>drop in</quote> a custom scheduler
- with its attendant custom properties <emphasis>without</emphasis> altering
- the rest of your application.
- </para>
- <para>
- Instead of deriving a custom scheduler fiber properties subclass from <link linkend="class_fiber"><code>fiber</code></link>,
- you must instead derive it from <link linkend="class_fiber_properties"><code>fiber_properties</code></link>.
- </para>
- <para>
- <programlisting><phrase role="keyword">class</phrase> <phrase role="identifier">priority_props</phrase> <phrase role="special">:</phrase> <phrase role="keyword">public</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber_properties</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">priority_props</phrase><phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">):</phrase>
- <phrase role="identifier">fiber_properties</phrase><phrase role="special">(</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">),</phrase> <co id="fiber.custom.c0" linkends="fiber.custom.c1" />
- <phrase role="identifier">priority_</phrase><phrase role="special">(</phrase> <phrase role="number">0</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">get_priority</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">priority_</phrase><phrase role="special">;</phrase> <co id="fiber.custom.c2" linkends="fiber.custom.c3" />
- <phrase role="special">}</phrase>
- <phrase role="comment">// Call this method to alter priority, because we must notify</phrase>
- <phrase role="comment">// priority_scheduler of any change.</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">set_priority</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">p</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase> <co id="fiber.custom.c4" linkends="fiber.custom.c5" />
- <phrase role="comment">// Of course, it's only worth reshuffling the queue and all if we're</phrase>
- <phrase role="comment">// actually changing the priority.</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">p</phrase> <phrase role="special">!=</phrase> <phrase role="identifier">priority_</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">priority_</phrase> <phrase role="special">=</phrase> <phrase role="identifier">p</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">notify</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// The fiber name of course is solely for purposes of this example</phrase>
- <phrase role="comment">// program; it has nothing to do with implementing scheduler priority.</phrase>
- <phrase role="comment">// This is a public data member -- not requiring set/get access methods --</phrase>
- <phrase role="comment">// because we need not inform the scheduler of any change.</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="identifier">name</phrase><phrase role="special">;</phrase> <co id="fiber.custom.c6" linkends="fiber.custom.c7" />
- <phrase role="keyword">private</phrase><phrase role="special">:</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">priority_</phrase><phrase role="special">;</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <calloutlist>
- <callout arearefs="fiber.custom.c0" id="fiber.custom.c1">
- <para>
- Your subclass constructor must accept a <literal><link linkend="class_context"><code>context</code></link>*</literal>
- and pass it to the <code><phrase role="identifier">fiber_properties</phrase></code>
- constructor.
- </para>
- </callout>
- <callout arearefs="fiber.custom.c2" id="fiber.custom.c3">
- <para>
- Provide read access methods at your own discretion.
- </para>
- </callout>
- <callout arearefs="fiber.custom.c4" id="fiber.custom.c5">
- <para>
- It's important to call <code><phrase role="identifier">notify</phrase><phrase
- role="special">()</phrase></code> on any change in a property that can
- affect the scheduler's behavior. Therefore, such modifications should only
- be performed through an access method.
- </para>
- </callout>
- <callout arearefs="fiber.custom.c6" id="fiber.custom.c7">
- <para>
- A property that does not affect the scheduler does not need access methods.
- </para>
- </callout>
- </calloutlist>
- <bridgehead renderas="sect3" id="fiber.custom.h2">
- <phrase id="fiber.custom.custom_scheduler_class"/><link linkend="fiber.custom.custom_scheduler_class">Custom
- Scheduler Class</link>
- </bridgehead>
- <para>
- Now we can derive a custom scheduler from <link linkend="class_algorithm_with_properties"><code>algorithm_with_properties<></code></link>,
- specifying our custom property class <code><phrase role="identifier">priority_props</phrase></code>
- as the template parameter.
- </para>
- <para>
- <programlisting><phrase role="keyword">class</phrase> <phrase role="identifier">priority_scheduler</phrase> <phrase role="special">:</phrase>
- <phrase role="keyword">public</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">algo</phrase><phrase role="special">::</phrase><phrase role="identifier">algorithm_with_properties</phrase><phrase role="special"><</phrase> <phrase role="identifier">priority_props</phrase> <phrase role="special">></phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">private</phrase><phrase role="special">:</phrase>
- <phrase role="keyword">typedef</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">scheduler</phrase><phrase role="special">::</phrase><phrase role="identifier">ready_queue_type</phrase><co id="fiber.custom.c8" linkends="fiber.custom.c9" /> <phrase role="identifier">rqueue_t</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">rqueue_t</phrase> <phrase role="identifier">rqueue_</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="identifier">mtx_</phrase><phrase role="special">{};</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">condition_variable</phrase> <phrase role="identifier">cnd_</phrase><phrase role="special">{};</phrase>
- <phrase role="keyword">bool</phrase> <phrase role="identifier">flag_</phrase><phrase role="special">{</phrase> <phrase role="keyword">false</phrase> <phrase role="special">};</phrase>
- <phrase role="keyword">public</phrase><phrase role="special">:</phrase>
- <phrase role="identifier">priority_scheduler</phrase><phrase role="special">()</phrase> <phrase role="special">:</phrase>
- <phrase role="identifier">rqueue_</phrase><phrase role="special">()</phrase> <phrase role="special">{</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// For a subclass of algorithm_with_properties<>, it's important to</phrase>
- <phrase role="comment">// override the correct awakened() overload.</phrase>
- <co id="fiber.custom.c10" linkends="fiber.custom.c11" /><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">,</phrase> <phrase role="identifier">priority_props</phrase> <phrase role="special">&</phrase> <phrase role="identifier">props</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">int</phrase> <phrase role="identifier">ctx_priority</phrase> <phrase role="special">=</phrase> <phrase role="identifier">props</phrase><phrase role="special">.</phrase><phrase role="identifier">get_priority</phrase><phrase role="special">();</phrase> <co id="fiber.custom.c12" linkends="fiber.custom.c13" />
- <phrase role="comment">// With this scheduler, fibers with higher priority values are</phrase>
- <phrase role="comment">// preferred over fibers with lower priority values. But fibers with</phrase>
- <phrase role="comment">// equal priority values are processed in round-robin fashion. So when</phrase>
- <phrase role="comment">// we're handed a new context*, put it at the end of the fibers</phrase>
- <phrase role="comment">// with that same priority. In other words: search for the first fiber</phrase>
- <phrase role="comment">// in the queue with LOWER priority, and insert before that one.</phrase>
- <phrase role="identifier">rqueue_t</phrase><phrase role="special">::</phrase><phrase role="identifier">iterator</phrase> <phrase role="identifier">i</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">find_if</phrase><phrase role="special">(</phrase> <phrase role="identifier">rqueue_</phrase><phrase role="special">.</phrase><phrase role="identifier">begin</phrase><phrase role="special">(),</phrase> <phrase role="identifier">rqueue_</phrase><phrase role="special">.</phrase><phrase role="identifier">end</phrase><phrase role="special">(),</phrase>
- <phrase role="special">[</phrase><phrase role="identifier">ctx_priority</phrase><phrase role="special">,</phrase><phrase role="keyword">this</phrase><phrase role="special">](</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase> <phrase role="special">&</phrase> <phrase role="identifier">c</phrase><phrase role="special">)</phrase>
- <phrase role="special">{</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">properties</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase><phrase role="identifier">c</phrase> <phrase role="special">).</phrase><phrase role="identifier">get_priority</phrase><phrase role="special">()</phrase> <phrase role="special"><</phrase> <phrase role="identifier">ctx_priority</phrase><phrase role="special">;</phrase> <phrase role="special">}));</phrase>
- <phrase role="comment">// Now, whether or not we found a fiber with lower priority,</phrase>
- <phrase role="comment">// insert this new fiber here.</phrase>
- <phrase role="identifier">rqueue_</phrase><phrase role="special">.</phrase><phrase role="identifier">insert</phrase><phrase role="special">(</phrase> <phrase role="identifier">i</phrase><phrase role="special">,</phrase> <phrase role="special">*</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <co id="fiber.custom.c14" linkends="fiber.custom.c15" /><phrase role="keyword">virtual</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">pick_next</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// if ready queue is empty, just tell caller</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="identifier">rqueue_</phrase><phrase role="special">.</phrase><phrase role="identifier">empty</phrase><phrase role="special">()</phrase> <phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">return</phrase> <phrase role="keyword">nullptr</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">(</phrase> <phrase role="special">&</phrase> <phrase role="identifier">rqueue_</phrase><phrase role="special">.</phrase><phrase role="identifier">front</phrase><phrase role="special">()</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">rqueue_</phrase><phrase role="special">.</phrase><phrase role="identifier">pop_front</phrase><phrase role="special">();</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <co id="fiber.custom.c16" linkends="fiber.custom.c17" /><phrase role="keyword">virtual</phrase> <phrase role="keyword">bool</phrase> <phrase role="identifier">has_ready_fibers</phrase><phrase role="special">()</phrase> <phrase role="keyword">const</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">return</phrase> <phrase role="special">!</phrase> <phrase role="identifier">rqueue_</phrase><phrase role="special">.</phrase><phrase role="identifier">empty</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <co id="fiber.custom.c18" linkends="fiber.custom.c19" /><phrase role="keyword">virtual</phrase> <phrase role="keyword">void</phrase> <phrase role="identifier">property_change</phrase><phrase role="special">(</phrase> <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">context</phrase> <phrase role="special">*</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">,</phrase> <phrase role="identifier">priority_props</phrase> <phrase role="special">&</phrase> <phrase role="identifier">props</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// Although our priority_props class defines multiple properties, only</phrase>
- <phrase role="comment">// one of them (priority) actually calls notify() when changed. The</phrase>
- <phrase role="comment">// point of a property_change() override is to reshuffle the ready</phrase>
- <phrase role="comment">// queue according to the updated priority value.</phrase>
- <phrase role="comment">// 'ctx' might not be in our queue at all, if caller is changing the</phrase>
- <phrase role="comment">// priority of (say) the running fiber. If it's not there, no need to</phrase>
- <phrase role="comment">// move it: we'll handle it next time it hits awakened().</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="special">!</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">-></phrase><phrase role="identifier">ready_is_linked</phrase><phrase role="special">())</phrase> <phrase role="special">{</phrase> <co id="fiber.custom.c20" linkends="fiber.custom.c21" />
- <phrase role="keyword">return</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="comment">// Found ctx: unlink it</phrase>
- <phrase role="identifier">ctx</phrase><phrase role="special">-></phrase><phrase role="identifier">ready_unlink</phrase><phrase role="special">();</phrase>
- <phrase role="comment">// Here we know that ctx was in our ready queue, but we've unlinked</phrase>
- <phrase role="comment">// it. We happen to have a method that will (re-)add a context* to the</phrase>
- <phrase role="comment">// right place in the ready queue.</phrase>
- <phrase role="identifier">awakened</phrase><phrase role="special">(</phrase> <phrase role="identifier">ctx</phrase><phrase role="special">,</phrase> <phrase role="identifier">props</phrase><phrase role="special">);</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">suspend_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">time_point</phrase><phrase role="special">)</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
- <phrase role="keyword">if</phrase> <phrase role="special">(</phrase> <phrase role="special">(</phrase><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">chrono</phrase><phrase role="special">::</phrase><phrase role="identifier">steady_clock</phrase><phrase role="special">::</phrase><phrase role="identifier">time_point</phrase><phrase role="special">::</phrase><phrase role="identifier">max</phrase><phrase role="special">)()</phrase> <phrase role="special">==</phrase> <phrase role="identifier">time_point</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">></phrase> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx_</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">cnd_</phrase><phrase role="special">.</phrase><phrase role="identifier">wait</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="special">[</phrase><phrase role="keyword">this</phrase><phrase role="special">](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">flag_</phrase><phrase role="special">;</phrase> <phrase role="special">});</phrase>
- <phrase role="identifier">flag_</phrase> <phrase role="special">=</phrase> <phrase role="keyword">false</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase> <phrase role="keyword">else</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">></phrase> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx_</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">cnd_</phrase><phrase role="special">.</phrase><phrase role="identifier">wait_until</phrase><phrase role="special">(</phrase> <phrase role="identifier">lk</phrase><phrase role="special">,</phrase> <phrase role="identifier">time_point</phrase><phrase role="special">,</phrase> <phrase role="special">[</phrase><phrase role="keyword">this</phrase><phrase role="special">](){</phrase> <phrase role="keyword">return</phrase> <phrase role="identifier">flag_</phrase><phrase role="special">;</phrase> <phrase role="special">});</phrase>
- <phrase role="identifier">flag_</phrase> <phrase role="special">=</phrase> <phrase role="keyword">false</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">}</phrase>
- <phrase role="keyword">void</phrase> <phrase role="identifier">notify</phrase><phrase role="special">()</phrase> <phrase role="keyword">noexcept</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">unique_lock</phrase><phrase role="special"><</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">mutex</phrase> <phrase role="special">></phrase> <phrase role="identifier">lk</phrase><phrase role="special">(</phrase> <phrase role="identifier">mtx_</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">flag_</phrase> <phrase role="special">=</phrase> <phrase role="keyword">true</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">lk</phrase><phrase role="special">.</phrase><phrase role="identifier">unlock</phrase><phrase role="special">();</phrase>
- <phrase role="identifier">cnd_</phrase><phrase role="special">.</phrase><phrase role="identifier">notify_all</phrase><phrase role="special">();</phrase>
- <phrase role="special">}</phrase>
- <phrase role="special">};</phrase>
- </programlisting>
- </para>
- <calloutlist>
- <callout arearefs="fiber.custom.c8" id="fiber.custom.c9">
- <para>
- See <link linkend="ready_queue_t">ready_queue_t</link>.
- </para>
- </callout>
- <callout arearefs="fiber.custom.c10" id="fiber.custom.c11">
- <para>
- You must override the <link linkend="algorithm_with_properties_awakened"><code>algorithm_with_properties::awakened()</code></link>
- method.
- This is how your scheduler receives notification of a fiber that has become
- ready to run.
- </para>
- </callout>
- <callout arearefs="fiber.custom.c12" id="fiber.custom.c13">
- <para>
- <code><phrase role="identifier">props</phrase></code> is the instance of
- priority_props associated with the passed fiber <code><phrase role="identifier">ctx</phrase></code>.
- </para>
- </callout>
- <callout arearefs="fiber.custom.c14" id="fiber.custom.c15">
- <para>
- You must override the <link linkend="algorithm_with_properties_pick_next"><code>algorithm_with_properties::pick_next()</code></link>
- method.
- This is how your scheduler actually advises the fiber manager of the next
- fiber to run.
- </para>
- </callout>
- <callout arearefs="fiber.custom.c16" id="fiber.custom.c17">
- <para>
- You must override <link linkend="algorithm_with_properties_has_ready_fibers"><code>algorithm_with_properties::has_ready_fibers()</code></link>
- to
- inform the fiber manager of the state of your ready queue.
- </para>
- </callout>
- <callout arearefs="fiber.custom.c18" id="fiber.custom.c19">
- <para>
- Overriding <link linkend="algorithm_with_properties_property_change"><code>algorithm_with_properties::property_change()</code></link>
- is
- optional. This override handles the case in which the running fiber changes
- the priority of another ready fiber: a fiber already in our queue. In that
- case, move the updated fiber within the queue.
- </para>
- </callout>
- <callout arearefs="fiber.custom.c20" id="fiber.custom.c21">
- <para>
- Your <code><phrase role="identifier">property_change</phrase><phrase role="special">()</phrase></code>
- override must be able to handle the case in which the passed <code><phrase
- role="identifier">ctx</phrase></code> is not in your ready queue. It might
- be running, or it might be blocked.
- </para>
- </callout>
- </calloutlist>
- <para>
- Our example <code><phrase role="identifier">priority_scheduler</phrase></code>
- doesn't override <link linkend="algorithm_with_properties_new_properties"><code>algorithm_with_properties::new_properties()</code></link>:
- we're content with allocating <code><phrase role="identifier">priority_props</phrase></code>
- instances on the heap.
- </para>
- <bridgehead renderas="sect3" id="fiber.custom.h3">
- <phrase id="fiber.custom.replace_default_scheduler"/><link linkend="fiber.custom.replace_default_scheduler">Replace
- Default Scheduler</link>
- </bridgehead>
- <para>
- You must call <link linkend="use_scheduling_algorithm"><code>use_scheduling_algorithm()</code></link> at the start
- of each thread on which you want <emphasis role="bold">Boost.Fiber</emphasis>
- to use your custom scheduler rather than its own default <link linkend="class_round_robin"><code>round_robin</code></link>.
- Specifically, you must call <code><phrase role="identifier">use_scheduling_algorithm</phrase><phrase
- role="special">()</phrase></code> before performing any other <emphasis role="bold">Boost.Fiber</emphasis>
- operations on that thread.
- </para>
- <para>
- <programlisting><phrase role="keyword">int</phrase> <phrase role="identifier">main</phrase><phrase role="special">(</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">argc</phrase><phrase role="special">,</phrase> <phrase role="keyword">char</phrase> <phrase role="special">*</phrase><phrase role="identifier">argv</phrase><phrase role="special">[])</phrase> <phrase role="special">{</phrase>
- <phrase role="comment">// make sure we use our priority_scheduler rather than default round_robin</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">use_scheduling_algorithm</phrase><phrase role="special"><</phrase> <phrase role="identifier">priority_scheduler</phrase> <phrase role="special">>();</phrase>
- <phrase role="special">...</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <bridgehead renderas="sect3" id="fiber.custom.h4">
- <phrase id="fiber.custom.use_properties"/><link linkend="fiber.custom.use_properties">Use
- Properties</link>
- </bridgehead>
- <para>
- The running fiber can access its own <link linkend="class_fiber_properties"><code>fiber_properties</code></link> subclass
- instance by calling <link linkend="this_fiber_properties"><code>this_fiber::properties()</code></link>. Although
- <code><phrase role="identifier">properties</phrase><phrase role="special"><>()</phrase></code>
- is a nullary function, you must pass, as a template parameter, the <code><phrase
- role="identifier">fiber_properties</phrase></code> subclass.
- </para>
- <para>
- <programlisting><phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">this_fiber</phrase><phrase role="special">::</phrase><phrase role="identifier">properties</phrase><phrase role="special"><</phrase> <phrase role="identifier">priority_props</phrase> <phrase role="special">>().</phrase><phrase role="identifier">name</phrase> <phrase role="special">=</phrase> <phrase role="string">"main"</phrase><phrase role="special">;</phrase>
- </programlisting>
- </para>
- <para>
- Given a <link linkend="class_fiber"><code>fiber</code></link> instance still connected with a running fiber (that
- is, not <link linkend="fiber_detach"><code>fiber::detach()</code></link>ed), you may access that fiber's properties
- using <link linkend="fiber_properties"><code>fiber::properties()</code></link>. As with <code><phrase role="identifier">boost</phrase><phrase
- role="special">::</phrase><phrase role="identifier">this_fiber</phrase><phrase
- role="special">::</phrase><phrase role="identifier">properties</phrase><phrase
- role="special"><>()</phrase></code>, you must pass your <code><phrase
- role="identifier">fiber_properties</phrase></code> subclass as the template
- parameter.
- </para>
- <para>
- <programlisting><phrase role="keyword">template</phrase><phrase role="special"><</phrase> <phrase role="keyword">typename</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">></phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">launch</phrase><phrase role="special">(</phrase> <phrase role="identifier">Fn</phrase> <phrase role="special">&&</phrase> <phrase role="identifier">func</phrase><phrase role="special">,</phrase> <phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">string</phrase> <phrase role="keyword">const</phrase><phrase role="special">&</phrase> <phrase role="identifier">name</phrase><phrase role="special">,</phrase> <phrase role="keyword">int</phrase> <phrase role="identifier">priority</phrase><phrase role="special">)</phrase> <phrase role="special">{</phrase>
- <phrase role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">fibers</phrase><phrase role="special">::</phrase><phrase role="identifier">fiber</phrase> <phrase role="identifier">fiber</phrase><phrase role="special">(</phrase> <phrase role="identifier">func</phrase><phrase role="special">);</phrase>
- <phrase role="identifier">priority_props</phrase> <phrase role="special">&</phrase> <phrase role="identifier">props</phrase><phrase role="special">(</phrase> <phrase role="identifier">fiber</phrase><phrase role="special">.</phrase><phrase role="identifier">properties</phrase><phrase role="special"><</phrase> <phrase role="identifier">priority_props</phrase> <phrase role="special">>()</phrase> <phrase role="special">);</phrase>
- <phrase role="identifier">props</phrase><phrase role="special">.</phrase><phrase role="identifier">name</phrase> <phrase role="special">=</phrase> <phrase role="identifier">name</phrase><phrase role="special">;</phrase>
- <phrase role="identifier">props</phrase><phrase role="special">.</phrase><phrase role="identifier">set_priority</phrase><phrase role="special">(</phrase> <phrase role="identifier">priority</phrase><phrase role="special">);</phrase>
- <phrase role="keyword">return</phrase> <phrase role="identifier">fiber</phrase><phrase role="special">;</phrase>
- <phrase role="special">}</phrase>
- </programlisting>
- </para>
- <para>
- Launching a new fiber schedules that fiber as ready, but does <emphasis>not</emphasis>
- immediately enter its <emphasis>fiber-function</emphasis>. The current fiber
- retains control until it blocks (or yields, or terminates) for some other reason.
- As shown in the <code><phrase role="identifier">launch</phrase><phrase role="special">()</phrase></code>
- function above, it is reasonable to launch a fiber and immediately set relevant
- properties -- such as, for instance, its priority. Your custom scheduler can
- then make use of this information next time the fiber manager calls <link linkend="algorithm_with_properties_pick_next"><code>algorithm_with_properties::pick_next()</code></link>.
- </para>
- </section>
- <section id="fiber.rationale">
- <title><link linkend="fiber.rationale">Rationale</link></title>
- <bridgehead renderas="sect3" id="fiber.rationale.h0">
- <phrase id="fiber.rationale.preprocessor_defines"/><link linkend="fiber.rationale.preprocessor_defines">preprocessor
- defines</link>
- </bridgehead>
- <table frame="all" id="fiber.rationale.preopcessor_defines">
- <title>preopcessor defines</title>
- <tgroup cols="2">
- <thead>
- <row>
- <entry>
- </entry>
- <entry>
- </entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- <para>
- BOOST_FIBERS_NO_ATOMICS
- </para>
- </entry>
- <entry>
- <para>
- no <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">atomic</phrase><phrase role="special"><></phrase></code>
- used, inter-thread synchronization disabled
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- BOOST_FIBERS_SPINLOCK_STD_MUTEX
- </para>
- </entry>
- <entry>
- <para>
- use <code><phrase role="identifier">std</phrase><phrase role="special">::</phrase><phrase
- role="identifier">mutex</phrase></code> as spinlock instead of default
- <code><phrase role="identifier">XCHG</phrase></code>-sinlock with
- backoff
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- BOOST_FIBERS_SPIN_BACKOFF
- </para>
- </entry>
- <entry>
- <para>
- limit determines when to used <code><phrase role="identifier">std</phrase><phrase
- role="special">::</phrase><phrase role="identifier">this_thread</phrase><phrase
- role="special">::</phrase><phrase role="identifier">yield</phrase><phrase
- role="special">()</phrase></code> instead of mnemonic <code><phrase
- role="identifier">pause</phrase><phrase role="special">/</phrase><phrase
- role="identifier">yield</phrase></code> during busy wait (apllies
- on to <code><phrase role="identifier">XCHG</phrase></code>-spinlock)
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <para>
- BOOST_FIBERS_SINGLE_CORE
- </para>
- </entry>
- <entry>
- <para>
- allways call <code><phrase role="identifier">std</phrase><phrase
- role="special">::</phrase><phrase role="identifier">this_thread</phrase><phrase
- role="special">::</phrase><phrase role="identifier">yield</phrase><phrase
- role="special">()</phrase></code> without backoff during busy wait
- (apllies on to <code><phrase role="identifier">XCHG</phrase></code>-spinlock)
- </para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- <bridgehead renderas="sect3" id="fiber.rationale.h1">
- <phrase id="fiber.rationale.distinction_between_coroutines_and_fibers"/><link
- linkend="fiber.rationale.distinction_between_coroutines_and_fibers">distinction
- between coroutines and fibers</link>
- </bridgehead>
- <para>
- The fiber library extends the coroutine library by adding a scheduler and synchronization
- mechanisms.
- </para>
- <itemizedlist>
- <listitem>
- <simpara>
- a coroutine yields
- </simpara>
- </listitem>
- <listitem>
- <simpara>
- a fiber blocks
- </simpara>
- </listitem>
- </itemizedlist>
- <para>
- When a coroutine yields, it passes control directly to its caller (or, in the
- case of symmetric coroutines, a designated other coroutine). When a fiber blocks,
- it implicitly passes control to the fiber scheduler. Coroutines have no scheduler
- because they need no scheduler.<footnote id="fiber.rationale.f0">
- <para>
- <ulink url="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4024.pdf">'N4024:
- Distinguishing coroutines and fibers'</ulink>
- </para>
- </footnote>.
- </para>
- <bridgehead renderas="sect3" id="fiber.rationale.h2">
- <phrase id="fiber.rationale.what_about_transactional_memory"/><link linkend="fiber.rationale.what_about_transactional_memory">what
- about transactional memory</link>
- </bridgehead>
- <para>
- GCC supports transactional memory since version 4.7. Unfortunately tests show
- that transactional memory is slower (ca. 4x) than spinlocks using atomics.
- Once transactional memory is improved (supporting hybrid tm), spinlocks will
- be replaced by __transaction_atomic{} statements surrounding the critical sections.
- </para>
- <bridgehead renderas="sect3" id="fiber.rationale.h3">
- <phrase id="fiber.rationale.synchronization_between_fibers_running_in_different_threads"/><link
- linkend="fiber.rationale.synchronization_between_fibers_running_in_different_threads">synchronization
- between fibers running in different threads</link>
- </bridgehead>
- <para>
- Synchronization classes from <ulink url="http://www.boost.org/doc/libs/release/libs/thread/index.html">Boost.Thread</ulink>
- block the entire thread. In contrast, the synchronization classes from <emphasis
- role="bold">Boost.Fiber</emphasis> block only specific fibers, so that the
- scheduler can still keep the thread busy running other fibers in the meantime.
- The synchronization classes from <emphasis role="bold">Boost.Fiber</emphasis>
- are designed to be thread-safe, i.e. it is possible to synchronize fibers running
- in different threads as well as fibers running in the same thread. (However,
- there is a build option to disable cross-thread fiber synchronization support;
- see <link linkend="cross_thread_sync">this description</link>.)
- </para>
- <anchor id="spurious_wakeup"/>
- <bridgehead renderas="sect3" id="fiber.rationale.h4">
- <phrase id="fiber.rationale.spurious_wakeup"/><link linkend="fiber.rationale.spurious_wakeup">spurious
- wakeup</link>
- </bridgehead>
- <para>
- Spurious wakeup can happen when using <ulink url="http://en.cppreference.com/w/cpp/thread/condition_variable"><code><phrase
- role="identifier">std</phrase><phrase role="special">::</phrase><phrase role="identifier">condition_variable</phrase></code></ulink>:
- the condition variable appears to be have been signaled while the awaited condition
- may still be false. Spurious wakeup can happen repeatedly and is caused on
- some multiprocessor systems where making <code><phrase role="identifier">std</phrase><phrase
- role="special">::</phrase><phrase role="identifier">condition_variable</phrase></code>
- wakeup completely predictable would slow down all <code><phrase role="identifier">std</phrase><phrase
- role="special">::</phrase><phrase role="identifier">condition_variable</phrase></code>
- operations.<footnote id="fiber.rationale.f1">
- <para>
- David R. Butenhof <quote>Programming with POSIX Threads</quote>
- </para>
- </footnote>
- </para>
- <para>
- <link linkend="class_condition_variable"><code>condition_variable</code></link> is not subject to spurious wakeup.
- Nonetheless it is prudent to test the business-logic condition in a <code><phrase
- role="identifier">wait</phrase><phrase role="special">()</phrase></code> loop
- — or, equivalently, use one of the <code><phrase role="identifier">wait</phrase><phrase
- role="special">(</phrase> <phrase role="identifier">lock</phrase><phrase role="special">,</phrase>
- <phrase role="identifier">predicate</phrase> <phrase role="special">)</phrase></code>
- overloads.
- </para>
- <para>
- See also <link linkend="condition_variable_spurious_wakeups">No Spurious Wakeups</link>.
- </para>
- <bridgehead renderas="sect3" id="fiber.rationale.h5">
- <phrase id="fiber.rationale.migrating_fibers_between_threads"/><link linkend="fiber.rationale.migrating_fibers_between_threads">migrating
- fibers between threads</link>
- </bridgehead>
- <para>
- Support for migrating fibers between threads has been integrated. The user-defined
- scheduler must call <link linkend="context_detach"><code>context::detach()</code></link> on a fiber-context on the
- source thread and <link linkend="context_attach"><code>context::attach()</code></link> on the destination thread,
- passing the fiber-context to migrate. (For more information about custom schedulers,
- see <link linkend="custom">Customization</link>.) Examples <code><phrase role="identifier">work_sharing</phrase></code>
- and <code><phrase role="identifier">work_stealing</phrase></code> in directory
- <code><phrase role="identifier">examples</phrase></code> might be used as a
- blueprint.
- </para>
- <para>
- See also <link linkend="migration">Migrating fibers between threads</link>.
- </para>
- <bridgehead renderas="sect3" id="fiber.rationale.h6">
- <phrase id="fiber.rationale.support_for_boost_asio"/><link linkend="fiber.rationale.support_for_boost_asio">support
- for Boost.Asio</link>
- </bridgehead>
- <para>
- Support for <ulink url="http://www.boost.org/doc/libs/release/libs/asio/index.html">Boost.Asio</ulink>’s
- <emphasis>async-result</emphasis> is not part of the official API. However,
- to integrate with a <ulink url="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service.html"><code><phrase
- role="identifier">boost</phrase><phrase role="special">::</phrase><phrase role="identifier">asio</phrase><phrase
- role="special">::</phrase><phrase role="identifier">io_service</phrase></code></ulink>,
- see <link linkend="integration">Sharing a Thread with Another Main Loop</link>.
- To interface smoothly with an arbitrary Asio async I/O operation, see <link
- linkend="callbacks_asio">Then There’s <ulink url="http://www.boost.org/doc/libs/release/libs/asio/index.html">Boost.Asio</ulink></link>.
- </para>
- <bridgehead renderas="sect3" id="fiber.rationale.h7">
- <phrase id="fiber.rationale.tested_compilers"/><link linkend="fiber.rationale.tested_compilers">tested
- compilers</link>
- </bridgehead>
- <para>
- The library was tested with GCC-5.1.1, Clang-3.6.0 and MSVC-14.0 in c++11-mode.
- </para>
- <bridgehead renderas="sect3" id="fiber.rationale.h8">
- <phrase id="fiber.rationale.supported_architectures"/><link linkend="fiber.rationale.supported_architectures">supported
- architectures</link>
- </bridgehead>
- <para>
- <emphasis role="bold">Boost.Fiber</emphasis> depends on <ulink url="http://www.boost.org/doc/libs/release/libs/context/index.html">Boost.Context</ulink>
- - the list of supported architectures can be found <ulink url="http://www.boost.org/doc/libs/release/libs/context/doc/html/context/architectures.html">here</ulink>.
- </para>
- </section>
- <section id="fiber.acknowledgements">
- <title><link linkend="fiber.acknowledgements">Acknowledgments</link></title>
- <para>
- I'd like to thank Agustín Bergé, Eugene Yakubovich, Giovanni Piero Deretta
- and especially Nat Goodspeed.
- </para>
- </section>
- </library>
|