您的位置:首页 > 移动开发 > IOS开发

iOS并发编程

2016-03-08 13:44 666 查看
iOS和OSX使用异步设计方法(asynchronousdesignapproach)去解决并发的问题,而不是直接使用线程。以下是两种解决并发执行的方法:

GrandCentralDispatch(GCD)

GCD帮组管理线程代码并把这部分代码移到系统层次。开发者需要做的只是定义需要完成的任务然后把其放到合适的dispatchqueue(下面简写为DQ)中。GCD负责创建必须的线程和在这些线程上调度任务。

Operationqueues

OperationQueues(下面简写为OQ)是Obj-C的对象,工作原理基本和DQ一样。所有的线程管理都由OQ管理。

一些重要概念的简单解释:

DispatchQueues

DQ是执行自定义任务的基于C的机制。DQ不管是串行还是并行,都是FIFO的。

DispatchSources

dispatchsource是用于处理系统各种特定类型事件的机制。DS封装一些必要的信息,例如系统事件的类型,并会在事件发生的时候,向DQ提交一个特定的block或者函数。

系统事件包括:

Timers

Signalhandlers

Descriptor-relatedevents

Process-relatedevents

Machportevents

Customeventsthatyoutrigger

OperationQueues

OQ是在Cocoa框架中等价于并发dispatchqueue的东西,它实现NSOperationQueue。相对于DQ按FIFO的顺序执行任务,OQ引入其他的因素决定执行顺序。最原始的一个因素是任务的执行是否受另外一些任务执行完成的影响。在定义任务的时候配置这些因素并且使用它们去创建一个复杂的执行顺序路径。

TipsforImprovingEfficiency

Inadditiontosimplyfactoringyourcodeintosmallertasksandaddingthemtoaqueue,thereareotherwaystoimprovetheoverallefficiencyofyourcodeusingqueues:

Considercomputingvaluesdirectlywithinyourtaskifmemoryusageisafactor.Ifyourapplicationisalreadymemorybound,computingvaluesdirectlynowmaybefasterthanloadingcachedvaluesfrommainmemory.Computingvaluesdirectlyusestheregistersandcachesofthegivenprocessorcore,whicharemuchfasterthanmainmemory.Ofcourse,youshouldonlydothisiftestingindicatesthisisaperformancewin.

Identifyserialtasksearlyanddowhatyoucantomakethemmoreconcurrent.Ifataskmustbeexecutedseriallybecauseitreliesonsomesharedresource,considerchangingyourarchitecturetoremovethatsharedresource.Youmightconsidermakingcopiesoftheresourceforeachclientthatneedsoneoreliminatetheresourcealtogether.

Avoidusinglocks.Thesupportprovidedbydispatchqueuesandoperationqueuesmakeslocksunnecessaryinmostsituations.Insteadofusinglockstoprotectsomesharedresource,designateaserialqueue(oruseoperationobjectdependencies)toexecutetasksinthecorrectorder.

Relyonthesystemframeworkswheneverpossible.Thebestwaytoachieveconcurrencyistotakeadvantageofthebuilt-inconcurrencyprovidedbythesystemframeworks.Manyframeworksusethreadsandothertechnologiesinternallytoimplementconcurrentbehaviors.Whendefiningyourtasks,looktoseeifanexistingframeworkdefinesafunctionormethodthatdoesexactlywhatyouwantanddoessoconcurrently.UsingthatAPImaysaveyoueffortandismorelikelytogiveyouthemaximumconcurrencypossible.

DispatchQueues

GCD自动提供一些DQ,当然也可以根据需求创建必须的自定义的。

Table3-1Typesofdispatchqueues

Type

Description

Serial

Serialqueues(alsoknownasprivatedispatchqueues)executeonetaskatatimeintheorderinwhichtheyareaddedtothequeue.Thecurrentlyexecutingtaskrunsonadistinctthread(whichcanvaryfromtasktotask)thatismanagedbythedispatchqueue.Serialqueuesareoftenusedtosynchronizeaccesstoaspecificresource.

Youcancreateasmanyserialqueuesasyouneed,andeachqueueoperatesconcurrentlywithrespecttoallotherqueues.Inotherwords,ifyoucreatefourserialqueues,eachqueueexecutesonlyonetaskatatimebutuptofourtaskscouldstillexecuteconcurrently,onefromeachqueue.Forinformationonhowtocreateserialqueues,see“CreatingSerialDispatchQueues.”

Concurrent

Concurrentqueues(alsoknownasatypeofglobaldispatchqueue)executeoneormoretasksconcurrently,buttasksarestillstartedintheorderinwhichtheywereaddedtothequeue.Thecurrentlyexecutingtasksrunondistinctthreadsthataremanagedbythedispatchqueue.Theexactnumberoftasksexecutingatanygivenpointisvariableanddependsonsystemconditions.

IniOS5andlater,youcancreateconcurrentdispatchqueuesyourselfbyspecifying
DISPATCH_QUEUE_CONCURRENT
asthequeuetype.Inaddition,therearefourpredefinedglobalconcurrentqueuesforyourapplicationtouse.Formoreinformationonhowtogettheglobalconcurrentqueues,see“GettingtheGlobalConcurrentDispatchQueues.”

Maindispatchqueue

Themaindispatchqueueisagloballyavailableserialqueuethatexecutestasksontheapplication’smainthread.Thisqueueworkswiththeapplication’srunloop(ifoneispresent)tointerleavetheexecutionofqueuedtaskswiththeexecutionofothereventsourcesattachedtotherunloop.Becauseitrunsonyourapplication’smainthread,themainqueueisoftenusedasakeysynchronizationpointforanapplication.

Althoughyoudonotneedtocreatethemaindispatchqueue,youdoneedtomakesureyourapplicationdrainsitappropriately.Formoreinformationonhowthisqueueismanaged,see“PerformingTasksontheMainThread.”

DQ的好处是让你更多关注的是执行的任务,而不是去关心线程的创建和管理。

如果有两个在不同线程的任务需要访问一个共享的资源,如果使用线程需要使用锁去实现这个操作。如果使用DQ,可以把任务放到serialdispatchqueue中去,保证一个时刻只有一个任务在访问资源。这相对于使用锁去同步,有很多的性能优势。锁请求昂贵的kerneltrap不管是否抢占资源,但是DQ工作于用户进程空间,只有在必须的时候才会向内核调用。

对于运行在串行队列的任务,并不是并发的,但相对于使用lock的情况,线程的并发优势会大大降低甚至没有了,更重要的是,线程的创建消耗内核和用户空间的内存。DQ不用为它们的线程牺牲同样的内存,而且DQ使用的线程会保持繁忙并且是不阻塞的。

DQ的一些关键点:

Dispatchqueuesexecutetheirtasksconcurrentlywithrespecttootherdispatchqueues.Theserializationoftasksislimitedtothetasksinasingledispatchqueue.多DQ之间任务是并发的,单DQ内任务是串行的。

Thesystemdeterminesthetotalnumberoftasksexecutingatanyonetime.Thus,anapplicationwith100tasksin100differentqueuesmaynotexecuteallofthosetasksconcurrently(unlessithas100ormoreeffectivecores).

Thesystemtakesqueueprioritylevelsintoaccountwhenchoosingwhichnewtaskstostart.Forinformationabouthowtosetthepriorityofaserialqueue,see“ProvidingaCleanUpFunctionForaQueue.”

Tasksinaqueuemustbereadytoexecuteatthetimetheyareaddedtothequeue.(IfyouhaveusedCocoaoperationobjectsbefore,noticethatthisbehaviordiffersfromthemodeloperationsuse.)

Privatedispatchqueuesarereference-countedobjects.Inadditiontoretainingthequeueinyourowncode,beawarethatdispatchsourcescanalsobeattachedtoaqueueandalsoincrementitsretaincount.Thus,youmustmakesurethatalldispatchsourcesarecanceledandallretaincallsarebalancedwithanappropriatereleasecall.Formoreinformationaboutretainingandreleasingqueues,see“MemoryManagementforDispatchQueues.”Formoreinformationaboutdispatchsources,see“AboutDispatchSources.”

除了DQ外,GCD提供以下技术使用queue去管理代码:

Table3-2Technologiesthatusedispatchqueues

Technology

Description

Dispatchgroups

Adispatchgroupisawaytomonitorasetofblockobjectsforcompletion.(Youcanmonitortheblockssynchronouslyorasynchronouslydependingonyourneeds.)Groupsprovideausefulsynchronizationmechanismforcodethatdependsonthecompletionofothertasks.Formoreinformationaboutusinggroups,see“WaitingonGroupsofQueuedTasks.”

Dispatchsemaphores

Adispatchsemaphoreissimilartoatraditionalsemaphorebutisgenerallymoreefficient.Dispatchsemaphorescalldowntothekernelonlywhenthecallingthreadneedstobeblockedbecausethesemaphoreisunavailable.Ifthesemaphoreisavailable,nokernelcallismade.Foranexampleofhowtousedispatchsemaphores,see“UsingDispatchSemaphorestoRegulatetheUseofFiniteResources.”

Dispatchsources

Adispatchsourcegeneratesnotificationsinresponsetospecifictypesofsystemevents.Youcanusedispatchsourcestomonitoreventssuchasprocessnotifications,signals,anddescriptoreventsamongothers.Whenaneventoccurs,thedispatchsourcesubmitsyourtaskcodeasynchronouslytothespecifieddispatchqueueforprocessing.Formoreinformationaboutcreatingandusingdispatchsources,see“DispatchSources.”

Block使用的一些原则:

Forblocksthatyouplantoperformasynchronouslyusingadispatchqueue,itissafetocapturescalarvariablesfromtheparentfunctionormethodandusethemintheblock.However,youshouldnottrytocapturelargestructuresorotherpointer-basedvariablesthatareallocatedanddeletedbythecallingcontext.Bythetimeyourblockisexecuted,thememoryreferencedbythatpointermaybegone.Ofcourse,itissafetoallocatememory(oranobject)yourselfandexplicitlyhandoffownershipofthatmemorytotheblock.对于block,使用父方法的数量值是安全的,不要使用callingcontext分配和删除的大的结构体或者指针。当block执行的时候,那些指针指向的内存可能已经不存在了。

Dispatchqueuescopyblocksthatareaddedtothem,andtheyreleaseblockswhentheyfinishexecuting.Inotherwords,youdonotneedtoexplicitlycopyblocksbeforeaddingthemtoaqueue.DQ会复制添加到它们的block。

Althoughqueuesaremoreefficientthanrawthreadsatexecutingsmalltasks,thereisstilloverheadtocreatingblocksandexecutingthemonaqueue.Ifablockdoestoolittlework,itmaybecheapertoexecuteitinlinethandispatchittoaqueue.Thewaytotellifablockisdoingtoolittleworkistogathermetricsforeachpathusingtheperformancetoolsandcomparethem.不要让block执行开销比dispatch它到queue上还少

Donotcachedatarelativetotheunderlyingthreadandexpectthatdatatobeaccessiblefromadifferentblock.Iftasksinthesamequeueneedtosharedata,usethecontextpointerofthedispatchqueuetostorethedatainstead.Formoreinformationonhowtoaccessthecontextdataofadispatchqueue,see“StoringCustomContextInformationwithaQueue.”

使用DQ的上下文指针(contextpointer)去保存block之间的共享数据,而不是在一个block中缓存它并在另一个block中访问

IfyourblockcreatesmorethanafewObjective-Cobjects,youmightwanttoenclosepartsofyourblock’scodeinan@autoreleaseblocktohandlethememorymanagementforthoseobjects.AlthoughGCDdispatchqueueshavetheirownautoreleasepools,theymakenoguaranteesastowhenthosepoolsaredrained.Ifyourapplicationismemoryconstrained,creatingyourownautoreleasepoolallowsyoutofreeupthememoryforautoreleasedobjectsatmoreregularintervals.

如果在block中创建大量的Obj-C对象,请使用@autorelease

CreatingandManagingDispatchQueues

GettingtheGlobalConcurrentDispatchQueues

系统提供四条并发DQ。这四条DQ对于应用是全局的,它们之间的区别是优先级。

DISPATCH_QUEUE_PRIORITY_DEFAULT

DISPATCH_QUEUE_PRIORITY_HIGH

DISPATCH_QUEUE_PRIORITY_LOW

DISPATCH_QUEUE_PRIORITY_BACKGROUND

CreatingSerialDispatchQueues

相对于并发DQ,串行DQ是要自己显式创建和管理的。

StoringCustomContextInformationwithaQueue

所有的dispatch对象运行你关联自定义的上下文数据到该对象上。使用方法:

dispatch_set_context

dispatch_get_context

系统不会使用这些自定义的数据,这些数据的分配和析构都取决于你。

ProvidingaCleanUpFunctionForaQueue

创建串行DQ可以指定回收函数在queue被析构的时候,去做自定义的清理工作。

Listing3-3Installingaqueuecleanupfunction

voidmyFinalizerFunction(void*context)

{

MyDataContext*theData=(MyDataContext*)context;

//Cleanupthecontentsofthestructure

myCleanUpDataContextFunction(theData);

//Nowreleasethestructureitself.

free(theData);

}

dispatch_queue_tcreateMyQueue()

{

MyDataContext*data=(MyDataContext*)malloc(sizeof(MyDataContext));

myInitializeDataContextFunction(data);

//Createthequeueandsetthecontextdata.

dispatch_queue_tserialQueue=dispatch_queue_create("com.example.CriticalTaskQueue",NULL);

if(serialQueue)

{

dispatch_set_context(serialQueue,data);

dispatch_set_finalizer_f(serialQueue,&myFinalizerFunction);

}

returnserialQueue;

}

AddingTaskstoaQueue

Important:Youshouldnevercallthe
dispatch_sync
or
dispatch_sync_f
functionfromataskthatisexecutinginthesamequeuethatyouareplanningtopasstothefunction.Thisisparticularlyimportantforserialqueues,whichareguaranteedtodeadlock,butshouldalsobeavoidedforconcurrentqueues.

不要在执行中的任务中调用dispatch_sync和
dispatch_sync_f,而且传递给dispatch_sync
dispatch_sync_f的queue参数和这个任务的queue是同一个。




dispatch_queue_tmyCustomQueue;

myCustomQueue=dispatch_queue_create("com.example.MyCustomQueue",NULL);

dispatch_async(myCustomQueue,^{

printf("Dosomeworkhere.\n");

});

printf("Thefirstblockmayormaynothaverun.\n");

dispatch_sync(myCustomQueue,^{

printf("Dosomemoreworkhere.\n");

});

printf("Bothblockshavecompleted.\n");



PerformingaCompletionBlockWhenaTaskIsDone

被dispatch到queue的任务是与创建它的代码是独立运行的。很多时候,需要在任务执行完成后,执行一个回调。在DQ中,可以使用completionblock去取代传统的回调方法。completionblock就是需要dispatch到queue中的一段代码。

voidaverage_async(int*data,size_tlen,

dispatch_queue_tqueue,void(^block)(int))

{

//Retainthequeueprovidedbytheusertomake

//sureitdoesnotdisappearbeforethecompletion

//blockcanbecalled.

dispatch_retain(queue);

//Dotheworkonthedefaultconcurrentqueueandthen

//calltheuser-providedblockwiththeresults.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{

intavg=average(data,len);

dispatch_async(queue,^{block(avg);});

//Releasetheuser-providedqueuewhendone

dispatch_release(queue);

});

}

PerformingLoopIterationsConcurrently

对于需要执行循环并发的情况,可以使用
dispatch_apply
或者
dispatch_apply_f。这适用于执行顺序是不重要的情况。对于串行队列,使用这方法对性能是没有提升的。




Important:Likearegular
for
loop,the
dispatch_apply
and
dispatch_apply_f
functionsdonotreturnuntilallloopiterationsarecomplete.Youshouldthereforebecarefulwhencallingthemfromcodethatisalreadyexecutingfromthecontextofaqueue.Ifthequeueyoupassasaparametertothefunctionisaserialqueueandisthesameoneexecutingthecurrentcode,callingthesefunctionswilldeadlockthequeue.

Becausetheyeffectivelyblockthecurrentthread,youshouldalsobecarefulwhencallingthesefunctionsfromyourmainthread,wheretheycouldpreventyoureventhandlingloopfromrespondingtoeventsinatimelymanner.Ifyourloopcoderequiresanoticeableamountofprocessingtime,youmightwanttocallthesefunctionsfromadifferentthread.



和普通for循环一样,dispatch_apply和dispatch_apply_f会在所有的循环结束之后才会返回。所以,如果传递给dispatch_apply和dispatch_apply_f的queue参数是当前任务运行着的queue,而且这个queue是一个串行queue,那么这个调用这个方法就会导致queue死锁。




UsingObjective-CObjectsinYourTasks



每一个dispatchqueue持有自己的的autoreleasepool。






UsingDispatchSemaphorestoRegulatetheUseofFiniteResources

在访问一些有限的资源时,就需要用到dispatchsemaphores去控制这些任务的数量。dispatchsemaphores的好处时减少内核调用,只有在资源不足时才会内核调用并停止线程,知道信号量被标记。

使用dispatchsemaphores的顺序:

Whenyoucreatethesemaphore(usingthe
dispatch_semaphore_create
function),youcanspecifyapositiveintegerindicatingthenumberofresourcesavailable.

Ineachtask,call
dispatch_semaphore_wait
towaitonthesemaphore.

Whenthewaitcallreturns,acquiretheresourceanddoyourwork.

Whenyouaredonewiththeresource,releaseitandsignalthesemaphorebycallingthe
dispatch_semaphore_signal
function.

//Createthesemaphore,specifyingtheinitialpoolsize

dispatch_semaphore_tfd_sema=dispatch_semaphore_create(getdtablesize()/2);

//Waitforafreefiledescriptor

dispatch_semaphore_wait(fd_sema,DISPATCH_TIME_FOREVER);

fd=open("/etc/services",O_RDONLY);

//Releasethefiledescriptorwhendone

close(fd);

dispatch_semaphore_signal(fd_sema);

dispatch_semaphore_wait会时时资源数减1,如果为负数,通知内核阻塞线程。



WaitingonGroupsofQueuedTasks


dispatchgroup的作用时在某些任何执行完成之前阻塞线程。



dispatch_queue_tqueue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

dispatch_group_tgroup=dispatch_group_create();

//Addatasktothegroup

dispatch_group_async(group,queue,^{

//Someasynchronouswork

});

//Dosomeotherworkwhilethetasksexecute.

//Whenyoucannotmakeanymoreforwardprogress,

//waitonthegrouptoblockthecurrentthread.

dispatch_group_wait(group,DISPATCH_TIME_FOREVER);

//Releasethegroupwhenitisnolongerneeded.

dispatch_release(group);



DispatchQueuesandThreadSafety


对于线程安全的一些Tips:



Dispatchqueuesthemselvesarethreadsafe.Inotherwords,youcansubmittaskstoadispatchqueuefromanythreadonthesystemwithoutfirsttakingalockorsynchronizingaccesstothequeue.

Donotcallthe
dispatch_sync
functionfromataskthatisexecutingonthesamequeuethatyoupasstoyourfunctioncall.Doingsowilldeadlockthequeue.Ifyouneedtodispatchtothecurrentqueue,dosoasynchronouslyusingthe
dispatch_async
function.

Avoidtakinglocksfromthetasksyousubmittoadispatchqueue.Althoughitissafetouselocksfromyourtasks,whenyouacquirethelock,youriskblockingaserialqueueentirelyifthatlockisunavailable.Similarly,forconcurrentqueues,waitingonalockmightpreventothertasksfromexecutinginstead.Ifyouneedtosynchronizepartsofyourcode,useaserialdispatchqueueinsteadofalock.

Althoughyoucanobtaininformationabouttheunderlyingthreadrunningatask,itisbettertoavoiddoingso.Formoreinformationaboutthecompatibilityofdispatchqueueswiththreads,see“CompatibilitywithPOSIXThreads.”



DispatchSources

与底层系统交互往往需要耗费大量的时间。内核调用或者其他系统底层调用会导致上下文的改变,这会比在自己进程中的调用有更多的开销。所以很多系统库会提供异步接口去允许程序向系统异步提交请求。

GCD使用blcok和DQ向系统提交请求并得到相应的结果返回。



AboutDispatchSources

dispatchsources是协调系统底层事件处理的基础数据结构。GCD支持以下的类型的dispatchsources:

Timerdispatchsourcesgenerateperiodicnotifications.

SignaldispatchsourcesnotifyyouwhenaUNIXsignalarrives.

Descriptorsourcesnotifyyouofvariousfile-andsocket-basedoperations,suchas:

Whendataisavailableforreading

Whenitispossibletowritedata

Whenfilesaredeleted,moved,orrenamedinthefilesystem

Whenfilemetainformationchanges

Processdispatchsourcesnotifyyouofprocess-relatedevents,suchas:

Whenaprocessexits

Whenaprocessissuesa
fork
or
exec
typeofcall

Whenasignalisdeliveredtotheprocess

MachportdispatchsourcesnotifyyouofMach-relatedevents.

Customdispatchsourcesareonesyoudefineandtriggeryourself.

dispatchsource取代异步回调方法,实现响应相关的系统事件。配置dispatchsource时,需要指定监听的事件,DQ和用于处理事件的代码。当关心的事件发生时,dispatchsource会向指定的DQ提交block或者函数。

dispatchsource会retain相关联的DQ防止其被释放。

为防止DQ事件积压,dispatchsources实现了事件合并方案。如果在旧事件没有被处理或者执行前,新事件到达了,dispatchsource会合并两个事件的数据。根据事件类型,可能会取代旧事件或者更新旧事件中的数据。

CreatingDispatchSources

创建DS的步骤:

Createthedispatchsourceusingthe
dispatch_source_create
function.

Configurethedispatchsource:

Assignaneventhandlertothedispatchsource;see“WritingandInstallinganEventHandler.”

Fortimersources,setthetimerinformationusingthe
dispatch_source_set_timer
function;see“CreatingaTimer.”

Optionallyassignacancellationhandlertothedispatchsource;see“InstallingaCancellationHandler.”

Callthe
dispatch_resume
functiontostartprocessingevents;see“SuspendingandResumingDispatchSources.”

WritingandInstallinganEventHandler

使用dispatch_source_set_event_handler
或者dispatch_source_set_event_handler_f去设置事件handler。当事件发生,事件handler会被提交到DQ中等待处理。

两种类型的handler:

//Block-basedeventhandler

void(^dispatch_block_t)(void)

//Function-basedeventhandler

void(*dispatch_function_t)(void*)

在事件handler内部,可以从DS中获取关于事件的相关信息。

dispatch_source_tsource=dispatch_source_create(DISPATCH_SOURCE_TYPE_READ,

myDescriptor,0,myQueue);

dispatch_source_set_event_handler(source,^{

//Getsomedatafromthesourcevariable,whichiscaptured

//fromtheparentcontext.

size_testimated=dispatch_source_get_data(source);

//Continuereadingthedescriptor...

});

dispatch_resume(source);

事件handler中获取到的变量默认是只读的。虽然block特性支持修改这些变量在特定的情况下,但是不要尝试这样做。DS是异步执行事件handler的,所以内部获取的变量可能在执行的时候已经不存在。

以下方法,可以获取事件的信息:

Table4-1Gettingdatafromadispatchsource

Function

Description

dispatch_source_get_handle


Thisfunctionreturnstheunderlyingsystemdatatypethatthedispatchsourcemanages.

Foradescriptordispatchsource,thisfunctionreturnsan
int
typecontainingthedescriptorassociatedwiththedispatchsource.

Forasignaldispatchsource,thisfunctionreturnsan
int
typecontainingthesignalnumberforthemostrecentevent.

Foraprocessdispatchsource,thisfunctionreturnsa
pid_t
datastructurefortheprocessbeingmonitored.

ForaMachportdispatchsource,thisfunctionreturnsa
mach_port_t
datastructure.

Forotherdispatchsources,thevaluereturnedbythisfunctionisundefined.

dispatch_source_get_data


Thisfunctionreturnsanypendingdataassociatedwiththeevent.

Foradescriptordispatchsourcethatreadsdatafromafile,thisfunctionreturnsthenumberofbytesavailableforreading.

Foradescriptordispatchsourcethatwritesdatatoafile,thisfunctionreturnsapositiveintegerifspaceisavailableforwriting.

Foradescriptordispatchsourcethatmonitorsfilesystemactivity,thisfunctionreturnsaconstantindicatingthetypeofeventthatoccurred.Foralistofconstants,seethe
dispatch_source_vnode_flags_t
enumeratedtype.

Foraprocessdispatchsource,thisfunctionreturnsaconstantindicatingthetypeofeventthatoccurred.Foralistofconstants,seethe
dispatch_source_proc_flags_t
enumeratedtype.

ForaMachportdispatchsource,thisfunctionreturnsaconstantindicatingthetypeofeventthatoccurred.Foralistofconstants,seethe
dispatch_source_machport_flags_t
enumeratedtype.

Foracustomdispatchsource,thisfunctionreturnsthenewdatavaluecreatedfromtheexistingdataandthenewdatapassedtothe
dispatch_source_merge_data
function.

dispatch_source_get_mask


Thisfunctionreturnstheeventflagsthatwereusedtocreatethedispatchsource.

Foraprocessdispatchsource,thisfunctionreturnsamaskoftheeventsthatthedispatchsourcereceives.Foralistofconstants,seethe
dispatch_source_proc_flags_t
enumeratedtype.

ForaMachportdispatchsourcewithsendrights,thisfunctionreturnsamaskofthedesiredevents.Foralistofconstants,seethe
dispatch_source_mach_send_flags_t
enumeratedtype.

ForacustomORdispatchsource,thisfunctionreturnsthemaskusedtomergethedatavalues.

InstallingaCancellationHandler

Cancellationhandler的作用是用于在DS被release前清楚资源。多少类型的DS,Cancellationhandler是可选实现的,只有在对需要被更新的DS执行一些自定义行为时需要到。对于使用descriptor或者Machport的DS而言,必须提供Cancellationhandler去关闭它们。

可以通过
dispatch_source_set_cancel_handler
or
dispatch_source_set_cancel_handler_f
设置cancellationhandler。

ChangingtheTargetQueue

可以在任何时候使用
dispatch_set_target_queue
函数去修改创建DS时指定的queue。在需要改变DS的事件的优先级的时候,需要做这个操作。

这个操作时异步的,并不能保证即时执行。对于已经出列的在等待处理的事件handler,它会继续在前一个queue里面执行。

AssociatingCustomDatawithaDispatchSource

可以使用dispatch_set_context函数去关联自定义的数据到DS上。可以使用上文件指针去存储存储数据,如果存储了,旧必须要设置cancellationhandler去释放它。

CancelingaDispatchSource

​DS一直处于活动状态知道显式调用
dispatch_source_cancel
函数,cancel后还要清除掉它。

voidRemoveDispatchSource(dispatch_source_tmySource)

{

dispatch_source_cancel(mySource);

dispatch_release(mySource);

}

SuspendingandResumingDispatchSources

可以使用dispatch_suspend
dispatch_resume去暂停和重启DS。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: