SDK源码解读系列:《iOS与OSX多线程和内存管理》书摘之GCD内部实现(二)

Dipatch Source

GCD中除了主要的Dispatch Queue以外,还有不太引人注目的Dispatch Source。它是一种BSD系列内核惯有功能kqueue的封装。

kqueue是在XNU内核中由发生各种事件时,在应用程序层面来处理的技术。其CPU符合非常小,基本上不占用资源。kqueue可以说是应用程序处理XNU内核中的事件处理机制中最为优秀的。

Dispatch Source 可以处理以下事件。如表所示:

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);


 

你可能感兴趣的:(多线程,内核,文件系统,gcd)