有时候,我们不得不将一个任务sync至另一个queue中,但sync操作是一个具有潜在危险的操作:不当的sync会导致进程被锁死。
比如一个queue A,将任务T sync至queue B,而任务T中又将一个子任务 S sync至queue A中,这将必然导致A和B都锁死。
你也许会问,设计任务T时,本身就应该避免其子任务再次sync回A,但在实际工程中,更可能是现象是:任务T的子任务S又调用另外一个任务R,以此类推直至某个任务M,M会将子任务N sync至queue A,这样的深入嵌套往往难以被任务T的开发者考虑到,甚至对任务M全然不知晓。
dispatch_queue_t queueA; dispatch_queue_t queueB; void taskR() { printf("this is task R, do you copy?"); } void taskS() { dispatch_sync(queueA, ^{ taskR(); }); } void taskT() { dispatch_sync(queueB, ^{ taskS(); }); } int foo() { queueA = dispatch_queue_create("queueA", 0); queueB = dispatch_queue_create("queueB", 0); dispatch_sync(queueA, ^{ taskT(); }); dispatch_release(queueA); dispatch_release(queueB); return 0; }
所以我们可以编写出一种封装的sync函数(这里以objective-c示例),来保护这种卡死的现象,一旦检测到了卡死,可以打印一些debug消息来警告调用者,在开发环境中可以尽情的使用此函数,而在生产环境中,继续使用此函数也不会有什么问题。
函数如下:
+ (void)scheduleTask01:(void(^)())task targetQueue:(dispatch_queue_t)queue timeOut:(float)seconds { (seconds < 0.0) && (seconds = 0.0); dispatch_semaphore_t sem = dispatch_semaphore_create(0); dispatch_async(queue, ^{ task(); dispatch_semaphore_signal(sem); }); if (dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(seconds * NSEC_PER_SEC))) != 0) { NSLog(@"dispatch timeout sync: time out!"); } dispatch_release(sem); }
使用async dispatch配合dispatch_semaphore来模拟sync dispatch,使得设置超时时间成为可能。
评论模块尚未加载