定时器用了那么多年,从来没有想过如何自己实现,除了for循环加上线程的sleep,没有想到更好的方法。等看到代码
__weak typeof(self) _self = self;
_lock = dispatch_semaphore_create(1);
_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(_source, dispatch_time(DISPATCH_TIME_NOW, (start * NSEC_PER_SEC)), (interval * NSEC_PER_SEC), 0);
dispatch_source_set_event_handler(_source, ^{[_self fire];});
dispatch_resume(_source);
才明白,多线程那么古老的实现啊。
信号量
代码中_lock = dispatch_semaphore_create(1);
是使用了信号量semaphore。
在GCD中有三个函数是semaphore的操作,分别是:
- dispatch_semaphore_create 创建一个semaphore
- dispatch_semaphore_signal 发送一个信号
- dispatch_semaphore_wait 等待信号
- (void)dispatch
{
dispatch_group_t group = dispatch_group_create();
dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i = 0; i < 100; i++) {
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_group_async(group, queue, ^{
NSLog(@"i is %i", i);
sleep(2);
dispatch_semaphore_signal(semaphore);
});
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"结果");
}
创建一个初始值为10的semaphore,可以实现最多并发上限为10. 使用dispatch_semaphore_wait方法来阻止并发,如果信号量的值为0则一直等待。
- 调用dispatch_semaphore_wait时表示,需要使用资源,semaphore的value 减一。
- 调用dispatch_semaphore_signal时表示,需要放放资源,semaphore的value加以。
- 所以这2个方法的调用需要成对出现,不然会导致线程被无限的阻塞。
dispatch源
_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
创建一个定时器的dispatch源,DISPATCH_SOURCE_TYPE_TIMER为定时器类型。
定时器
dispatch_source_set_timer(_source, dispatch_time(DISPATCH_TIME_NOW, (start * NSEC_PER_SEC)), (interval * NSEC_PER_SEC), 0);
创建一个定时器,设置第一次触发的时间,间隔时间。
dispatch_source_set_event_handler(_source, ^{[_self fire];});
设置响应dispatch源事件的block,在分派源指定的队列上运行.
dispatch_resume(_source);
在dispatch源创建后默认是挂起的,需要用dispatch_resume函数来恢复监听。
定时器就创建完成了,主要使用GCD提供的方法来实现。
保证定时任务每次执行一条
- (void)invalidate {
dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
if (_valid) {
dispatch_source_cancel(_source);
_source = NULL;
_target = nil;
_valid = NO;
}
dispatch_semaphore_signal(_lock);
}
- (void)fire {
if (!_valid) return;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
id target = _target;
if (!target) {
dispatch_semaphore_signal(_lock);
[self invalidate];
} else {
dispatch_semaphore_signal(_lock);
[target performSelector:_selector withObject:self];
if (!_repeats) {
[self invalidate];
}
}
#pragma clang diagnostic pop
}
每次调用方法由定时器触发。因为semaphore初始化值为1,所以资源最多为1,保证每次只能执行一条。
// END