GCD 之dispatch source

概念介绍

event source:系统事件源,例如:unix信号,文件描述符,定时器等
dispatch source:是底层事件源的封装,可以理解跟事件源是同义词

创建 dispatch source

dispatch_source_t dispatch_source_create(dispatch_source_type_t type, uintptr_t handle, unsigned long mask, dispatch_queue_t queue);
  1. type:事件类型,比如:

    DISPATCH_SOURCE_TYPE_PROC
    DISPATCH_SOURCE_TYPE_READ
    DISPATCH_SOURCE_TYPE_SIGNAL
    DISPATCH_SOURCE_TYPE_TIMER
    DISPATCH_SOURCE_TYPE_VNODE
    DISPATCH_SOURCE_TYPE_WRITE
  2. handle:句柄,比如:fd, pid, signo, mach port 等
  3. mask:事件掩码
  4. queue:事件处理器执行的队列

配置 dispatch source

dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, queue);
dispatch_source_set_event_handler(source, ^{
    size_t size = dispatch_source_get_data(source);
    read(fd, buf, size);
});
dispatch_source_set_cancel_handler(source, ^{
   close(fd);
});
dispatch_resume(source);  // 启动

install 事件处理器

dispatch_source_set_event_handler(source, ^{
    size_t size = dispatch_source_get_data(source);
    read(fd, buf, size);
});

install cacnel handler

dispatch_source_set_cancel_handler(source, ^{
   close(fd);
});

uninstall 事件处理器

dispatch_source_cancel(source);

uninstall 事件处理器会调用通过dispatch_source_set_cancel_handler函数安装的cancel handler

销毁 dispatch source (非arc)

dispatch_release(source);

从 dispatch source 获取数据

dispatch_source_get_handle
dispatch_source_get_data
dispatch_source_get_mask

改变队列

创建dispatch source时指定的队列可以被改变,使用函数

dispatch_set_target_queue

创建定时器

dispatch_source_t create_timer(dispatch_queue_t queue, uint64_t interval, dispatch_block_t block)
{
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    if (timer) {
        dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, (int64_t)interval), interval, 0);
        dispatch_source_set_event_handler(timer, block);
        dispatch_resume(timer);
    }
    return timer;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    _timer = create_timer(dispatch_get_main_queue(), 2 * NSEC_PER_SEC, ^{
        // do something
    });
}

延迟执行


    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        // do something
    });

从文件描述符读数据

typedef dispatch_source_t file_reader_t;

file_reader_t file_reader_create(const std::string &path, void (^block)(const std::vector<uint8_t> &data, bool *stop))
{
    int fd;
    do {
        fd = open(path.c_str(), O_RDONLY);
    }
    while (fd == -1 && errno == EINTR);
    if (fd == -1)
        return nullptr;

    fcntl(fd, F_SETFL, O_NONBLOCK);  // Avoid blocking the read operation

    auto read_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, DISPATCH_TARGET_QUEUE_DEFAULT);
    dispatch_source_set_event_handler(read_source, ^{
        auto size = dispatch_source_get_data(read_source);
        std::vector<uint8_t> buf(size);
        auto n = read(fd, buf.data(), buf.size());
        buf.resize(n);
        bool stop = false;
        block(buf, &stop);
        if (stop)
            dispatch_source_cancel(read_source);
    });
    dispatch_source_set_cancel_handler(read_source, ^{
        close(fd);
    });
    dispatch_resume(read_source);
    return read_source;
}
- (void)viewDidLoad
{
    [super viewDidLoad];

    _file_reader = file_reader_create("/path/to/file", ^(const std::vector<uint8_t> &data, bool *stop) {
        std::string s(data.cbegin(), data.cend());
        std::cout << s;
    });
}

这个用法类似:

[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    // do something
}];

监控vnode

dispatch_source_t vnode_monitor_create(const std::string &path, dispatch_source_vnode_flags_t flags, std::function<void(int fd, bool *stop)> block)
{
    int fd;
    do {
        fd = open(path.c_str(), O_EVTONLY);
    }
    while (fd == -1 && errno == EINTR);
    if (fd == -1)
        return nullptr;

    dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, flags, DISPATCH_TARGET_QUEUE_DEFAULT);
    dispatch_source_set_event_handler(source, ^{
        bool stop = false;
        block(fd, &stop);
        if (stop)
            dispatch_source_cancel(source);
    });
    dispatch_source_set_cancel_handler(source, ^{
        close(fd);
    });
    dispatch_resume(source);
    return source;
}

监控unix信号

dispatch_source_t signal_monitor_create(int signo, std::function<void(int signo, bool *stop)> block)
{
    // Make sure the signal does not terminate the application.
    signal(signo, SIG_IGN);

    dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, signo, 0, DISPATCH_TARGET_QUEUE_DEFAULT);
    dispatch_source_set_event_handler(source, ^{
        bool stop = false;
        block(signo, &stop);
        if (stop)
            dispatch_source_cancel(source);
    });
    dispatch_resume(source);
    return source;
}

传统上,应用程序使用sigaction函数来安装信号处理函数
gcd signal dispatch source 并不能代替传统的sigaction
gcd signal dispatch source 不能监控 SIGILL, SIGBUS, and SIGSEGV 等信号
gcd signal dispatch source 也不能阻止进程收到信号时的默认行为
通过sigaction安装的信号处理函数是同步执行的,并且功能是受限制的
gcd signal dispatch source 的信号处理函数是异步执行的,并且功能不受任何限制
gcd signal dispatch source 的信号处理函数不会被其他信号处理函数覆盖

监控进程

dispatch_source_t process_monitor_create(pid_t pid, dispatch_source_proc_flags_t flags, std::function<void(pid_t pid, bool *stop)> block)
{
    dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid, flags, DISPATCH_TARGET_QUEUE_DEFAULT);
    dispatch_source_set_event_handler(source, ^{
        bool stop = false;
        block(pid, &stop);
        if (stop)
            dispatch_source_cancel(source);
    });
    dispatch_resume(source);
    return source;
}

挂起和恢复

dispatch_suspend
dispatch_resume
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值