GCD全解-10-dispatch_source

版权声明:知识版权是属于全人类的! 欢迎评论与转载!!! https://blog.csdn.net/zhuge1127/article/details/82526109

现代系统通常提供异步接口,允许应用向系统提交请求,然后在系统处理请求时应用可以继续处理自己的事情。

Grand Central Dispatch正是基于这个基本行为而设计,允许你提交请求,并通过block和dispatch queue报告结果。

dispatch source是基础数据类型,协调特定底层系统事件的处理
Dispatch source替代了异步回调函数,来处理系统相关的事件。

当你配置一个dispatch source时,你指定要监测的事件、dispatch queue、以及处理事件的代码(block或函数)。

当事件发生时,dispatch source会提交你的block或函数到指定的queue去执行和手工提交到queue的任务不同,dispatch source为应用提供连续的事件源。除非你显式地取消,dispatch source会一直保留与dispatch queue的关联。

只要相应的事件发生,就会提交关联的代码到dispatch queue去执行。
为了防止事件积压到dispatch queue,dispatch source实现了事件合并机制。
如果新事件在上一个事件处理器出列并执行之前到达,dispatch source会将新旧事件的数据合并。
根据事件类型的不同,合并操作可能会替换旧事件,或者更新旧事件的信息。

它是BSD系内核惯有功能kqueue的包装。kqueue是在XUN内核中发生各种事件时,在应用程序编程方执行处理的技术。
其CPU负荷非常小,尽量不占用资源。kqueue可以说是应用程序处理XUN内核中发生的各种事件的方法中最优秀的一种。

dispatch_source的类型

typedef const struct dispatch_source_type_s *dispatch_source_type_t;

/*
当同一时间,一个事件的的触发频率很高,那么Dispatch Source会将这些响应以ADD的方式进行累积,然后等系统空闲时最终处理,如果触发频率比较零散,那么Dispatch Source会将这些事件分别响应。
*/
DISPATCH_SOURCE_TYPE_DATA_ADD        自定义的事件,变量增加
DISPATCH_SOURCE_TYPE_DATA_OR         自定义的事件,变量OR
DISPATCH_SOURCE_TYPE_DATA_REPLACE    自定义的事件,变量Replace
DISPATCH_SOURCE_TYPE_MACH_SEND       MACH端口发送    
DISPATCH_SOURCE_TYPE_MACH_RECV       MACH端口接收 
DISPATCH_SOURCE_TYPE_MEMORYPRESSURE  内存报警
DISPATCH_SOURCE_TYPE_PROC            进程监听,如进程的退出、创建一个或更多的子线程、进程收到UNIX信号
DISPATCH_SOURCE_TYPE_READ            IO操作,如对文件的操作、socket操作的读响应
DISPATCH_SOURCE_TYPE_SIGNAL          接收到UNIX信号时响应
DISPATCH_SOURCE_TYPE_TIMER           定时器
DISPATCH_SOURCE_TYPE_VNODE           文件状态监听,文件被删除、移动、重命名
DISPATCH_SOURCE_TYPE_WRITE           IO操作,如对文件的操作、socket操作的写响应
DISPATCH_MACH_SEND_DEAD

//The system memory pressure condition has returned to normal.  
#define DISPATCH_MEMORYPRESSURE_NORMAL      0x01

//The system memory pressure condition has changed to warning.
#define DISPATCH_MEMORYPRESSURE_WARN        0x02

//The system memory pressure condition has changed to critical.
#define DISPATCH_MEMORYPRESSURE_CRITICAL    0x04 

创建Dispatch Source

创建dispatch source需要同时创建事件源和dispatch source本身。事件源是处理事件所需要的native数据结构
对于定时器源,使用 dispatch_source_set_timer 函数设置定时器信息
由于dispatch source必须进行额外的配置才能被使用,dispatch_source_create 函数返回的dispatch source将处于挂起状态。Dispatch sources are created in an inactive state.此时dispatch source会接收事件,但是不会进行处理。这时候你可以安装事件处理器,并执行额外的配置。

@param type Must be one of the defined dispatch_source_type_t constants.
@param handle The underlying system handle to monitor. The interpretation of this argument is determined by the constant provided in the type parameter.默认传入0就好了
@param mask A mask of flags specifying which events are desired. The interpretation of this argument is determined by the constant provided in the type parameter.

dispatch_source_t
dispatch_source_create(dispatch_source_type_t type,
                   uintptr_t handle,
                   unsigned long mask,
                   dispatch_queue_t _Nullable queue);     

设置事件处理器

定义一个事件处理器来处理事件,可以是函数或block对象,并使用 dispatch_source_set_event_handlerdispatch_source_set_event_handler_f 安装事件处理器。事件到达时,dispatch source会提交你的事件处理器到指定的dispatch queue,由queue执行事件处理器。
事件处理器的代码负责处理所有到达的事件。如果事件处理器已经在queue中并等待处理已经到达的事件,如果此时又来了一个新事件,dispatch source会合并这两个事件。事件处理器通常只能看到最新事件的信息,不过某些类型的dispatch source也能获得已经发生以及合并的事件信息。
如果事件处理器已经开始执行,一个或多个新事件到达,dispatch source会保留这些事件,直到前面的事件处理器完成执行。然后以新事件再次提交处理器到queue。
函数事件处理器有一个context指针指向dispatch source对象,没有返回值。Block事件处理器没有参数,也没有返回值。

void
dispatch_source_set_event_handler(dispatch_source_t source,
    dispatch_block_t _Nullable handler);

void
dispatch_source_set_event_handler_f(dispatch_source_t source,
    dispatch_function_t _Nullable handler);

取消处理器

取消处理器在dispatch soruce释放之前执行清理工作。
多数类型的dispatch source不需要取消处理器,除非你对dispatch source有自定义行为需要在释放时执行。
但是使用描述符或Mach port的dispatch source必须设置取消处理器,用来关闭描述符或释放Mach port。
否则可能导致微妙的bug,这些结构体会被系统其它部分或你的应用在不经意间重用。

你可以在任何时候安装取消处理器,但通常我们在创建dispatch source时就会安装取消处理器。使用 dispatch_source_set_cancel_handler 或 dispatch_source_set_cancel_handler_f 函数来设置取消处理器。

# 除非你显式地调用 dispatch_source_cancel 函数,dispatch source将一直保持活动,取消一个dispatch source会停止递送新事件,并且不能撤销。因此你通常在取消dispatch source后立即释放

# 取消一个dispatch source是异步操作,调用 dispatch_source_cancel 之后,不会再有新的事件被处理,但是正在被dispatch source处理的事件会继续被处理完成。在处理完最后的事件之后,dispatch source会执行自己的取消处理器。取消处理器是你最后的执行机会,在那里执行内存或资源的释放工作。例如描述符或mach port类型的dispatch source,必须提供取消处理器,用来关闭描述符或mach port  

void dispatch_source_cancel(dispatch_source_t source);
long dispatch_source_testcancel(dispatch_source_t source);

void dispatch_source_set_cancel_handler(dispatch_source_t source,
    dispatch_block_t _Nullable handler);

void dispatch_source_set_cancel_handler_f(dispatch_source_t source,
    dispatch_function_t _Nullable handler);

挂起和继续Dispatch Source

你可以使用 dispatch_suspend 和 dispatch_resume 临时地挂起和继续dispatch source的事件递送。这两个函数分别增加和减少dispatch 对象的挂起计数。因此,你必须每次 dispatch_suspend 调用之后,都需要相应的 dispatch_resume 才能继续事件递送。

挂起一个dispatch source期间,发生的任何事件都会被累积,直到dispatch source继续。但是不会递送所有事件,而是先合并到单一事件,然后再一次递送。例如你监控一个文件的文件名变化,就只会递送最后一次的变化事件。

猜你喜欢

转载自blog.csdn.net/zhuge1127/article/details/82526109