之前说过GCD中的serial queue是FIFO的执行次序,也就是说你依次添加进queue的任务会按照先后顺序执行完毕.
最近在做一个关于iCloud的项目,在更新文件夹内容变化的时候用到了serial queue,处理逻辑如下:
- (void)presentedSubitemDidChangeAtURL:(NSURL *)url{
NSDate *currentDate = [NSDate date];
myQueue = NULL;
if (myQueue == NULL) {
myQueue = dispatch_queue_create([[currentDate description] UTF8String], NULL);
}
dispatch_async(myQueue, ^{
//fetch the data
[array addObject:obj];
[self.tableView insertRowsAtIndexPaths:arr withRowAnimation:UITableViewRowAnimationFade];
});
}
即使有大批量文件上传,更新的时候逐步调用此函数.因为myQueue是个serial queue,更新的时候会依照先后顺序逐条更新.
但是实际测试的时候,比如上传50个文件的时候,程序往往会崩溃,错误原因大概是:
table view的datasource更新后的数目不等于更新前的数目和删除/添加的数目之和.
也就是说,array可能已经添加了好几个元素了,但是才做了一次UI的更新.
这就让我很奇怪,因为serial首先是FIFO的,并且每次执行的:获取数据-刷新UI的任务都是相同的,怎么还会发生这样的问题?
后来仔细看了下文档,可能是iOS5里有了变化,文档中提到:
Blocks submitted to a concurrent queue are dequeued in FIFO order but may run concurrently if resources are available to do so.
原来在某种情况下,serial queue会变成concurrently queue.但是什么情况下算是 "resources are available "的呢?有人说mac上双核的情况下,会发生这样的情况.但是我是在iTouch4上测试的,这按理也单核处理器啊.不管怎样,得想办法修改下,使得serial成为真正的FIFO.
解决的方法很简单,就是使用信号量了.于是,这个问题就变成了简单的同步问题了.