Dipatch Source
GCD中除了主要的Dispatch Queue以外,还有不太引人注目的Dispatch Source。它是一种BSD系列内核惯有功能kqueue的封装。
kqueue是在XNU内核中由发生各种事件时,在应用程序层面来处理的技术。其CPU符合非常小,基本上不占用资源。kqueue可以说是应用程序处理XNU内核中的事件处理机制中最为优秀的。
Dispatch Source 可以处理以下事件。如表所示:
名称 | 内容 |
---|---|
DISPATCH_SOURCE_TYPE_DATA_ADD | 增加变量 |
DISPATCH_SOURCE_TYPE_DATA_OR | 变量OR |
DISPATCH_SOURCE_TYPE_MACH_SEND | 通过MACH端口发送 |
DISPATCH_SOURCE_TYPE_MACH_RECV | 通过MACH端口接收 |
DISPATCH_SOURCE_TYPE_PROC | 检测进程相关事件 |
DISPATCH_SOURCE_TYPE_READ | 文件描述器变为可读 |
DISPATCH_SOURCE_TYPE_SIGNAL | 收到信号 |
DISPATCH_SOURCE_TYPE_TIMER | 定时器 |
DISPATCH_SOURCE_TYPE_VNODE | 文件系统被修改 |
DISPATCH_SOURCE_TYPE_WRITE | 文件描述器其变为可写 |
事件发生时,在指定的Dispatch Queue中可执行事件的处理。
下面我们看看DISPATCH_SOURCE_TYPE_READ方法是怎样来读取一个异步文件描述器的:
__block size_t total = 0;
size_t size = 读取的字节数;
char *buff = (char *)malloc(size);
/*
* 将sockfd设置为异步(NONBLOCK)式的描述器,一个文件描述器*/
fcntl(sockfd, F_SETFL, O_NONBLOCK);
/*
* 获取用于追加事件处理的Global Dispatch Queue.
*/
dispatch_queue_t queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/*
* 将READ事件创建为Dispatch Source.
*/
dispatch_source_t source =
dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, sockfd, 0, queue);
/*
* 为READ事件指定任务.
*/
dispatch_source_set_event_handler(source, ^{
/*
* 获取可读取的字节数.
*/
size_t available = dispatch_source_get_data(source); /*
* 从描述器中读取数据
*/
int length = read(sockfd, buff, available);
/*
* 当有错误发生时,取消Dispatch Source.
*/
if (length < 0) {
/*
* 错误处理
*/
dispatch_source_cancel(source);
}
total += length;
if (total == size) {
/*
* buff的处理
*/
/*
* 完成后取消dispatch source
*/dispatch_source_cancel(source);
}
});
/*
* 为dispatch source的取消事件设置任务
*/
dispatch_source_set_cancel_handler(source, ^{
free(buff);
close(sockfd);
/*
* 释放dispatch source自己
*/
dispatch_release(source);
});
/*
* 恢复dispatch source
*/
dispatch_resume(source);