我有,有时可以在我的代码中调用的方法。 下面是一个非常简单的例子,如代码处理图像和文件从iPhone照片库中,标志着在与方法做他们已经处理过。
@property (nonatomic, assign) dispatch_queue_t serialQueue;
....
-(void)processImages
{
dispatch_async(self.serialQueue, ^{
//block to process images
NSLog(@"In processImages");
....
NSLog(@"Done with processImages");
});
}
我倒觉得,每次调用此方法时,我会得到下面的输出......“在processImages”“与processImages完成”“在processImages”“与processImages”等完成...
但我总是
“在processImages”“在processImages”“完成与processImages”“与processImages”等完成...
我想到了一个串行队列会等待,直到第一个块完成,然后开始。 对我来说,似乎它已经开始的方法,那么它被再次调用,并启动了第一个电话,甚至完成之前,创建通常不会因处理这样的事实,图像,如果它真的串行执行的方法会知道他们的重复已经处理。 也许是我的串行队列的理解是不具体的。 任何输入? 谢谢。
编辑:下面更多的背景,这就是在块怎么回事?难道这会导致问题???
@property (nonatomic, assign) dispatch_queue_t serialQueue;
....
-(void)processImages
{
dispatch_async(self.serialQueue, ^{
//library is a reference to ALAssetsLibrary object
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop)
{
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop)
{
....
//Process the photos here
}];
failureBlock:^(NSError *error) { NSLog(@"Error loading images from library");
}];
});
}
-(id)init
{
self = [super init];
if(self)
{
_serialQueue = dispatch_queue_create("com.image.queue",NULL);
}
return self;
}
这个对象只创建一次,而据我可以告诉永远无法再创建基于关我的代码...我将进行测试,以确保虽然。
更新2:我认为正在发生的,请在此,如果你同意意见/不同意....
显然,我的主要问题是,它似乎正在被同时执行的代码块,创建重复条目(导入相同的图片两次)时,它通常不会做,如果它连续运行。 如果照片是处理的“脏”的位被施加到它确保下一次方法被调用它跳过该图像中,但是这是不会发生与一些图像被处理两次。 难道这是因为我在列举使用enumerategroupswithtypes第二队列中的对象的事实:即serialQueue内?
- 呼叫processImages
- enumerateObjects
- 立即从enumerateObjects返回,因为它是异步本身
- 结束通话到processImages
processImages是不是真的,虽然由于做了这样的事实,enumerategroups可能还在运行,但队列可能的事情,因为它达到enumerategroups之前完成工作块结束它完成。 这似乎是一个可能性,我呢?
串行队列绝对不会连续进行。 他们不能保证然而相同的线程上执行。
假设你使用的是相同的序列队列中,存在的问题是,从不同的线程几乎同时调用时的NSLog不能保证正确的顺序输出结果。
这里有一个例子:
- SQ运行在线程X,将“在processImages”
- 日志打印“在PROC”
- 上线X SQ,发送“完成与processImages”
- SQ运行在线程Y,将“在processImages”
- 日志打印 “essImages的\ n”
5.后的NSLog并不一定知道哪个打印,3或4。
如果你确实需要时间排序的记录,您需要登录一个专门的队列。 在实践中,我已经与只使用主队列中没有问题:
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"whatever");
});
如果所有的NSLog调用是在同一个队列,你不应该有这个问题。
如果问题是“CAN串行队列执行任务异步?” 那么答案是否定的。 如果你认为它可以,你应该确保所有任务都真正执行在同一个队列。 您可以在模块中添加以下行,比较输出:
dispatch_async(self.serialQueue, ^{
NSLog(@"current queue:%p current thread:%@",dispatch_get_current_queue(),[NSThread currentThread]);
请确保您在您的队列中,而不是在enumerateGroupsWithTypes执行块写的NSLog:usingBlock:failureBlock:您也可以尝试创建自己的队列是这样
dispatch_queue_create("label", DISPATCH_QUEUE_SERIAL);
但我不认为这会改变什么
编辑:顺便说一句,方法
enumerateGroupsWithTypes:usingBlock:failureBlock:
是异步的,你为什么把它叫做另一个队列?
更新2:我可以建议是这样的:
dispatch_async(queue, ^{
NSLog(@"queue");
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER, *pmutex = &mutex;
pthread_mutex_lock(pmutex);
ALAssetsLibraryGroupsEnumerationResultsBlock listGroupBlock = ^(ALAssetsGroup *group, BOOL *stop) {
NSLog(@"block");
if (group) {
[groups addObject:group];
} else {
[self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
dispatch_async(dispatch_get_current_queue(), ^{
pthread_mutex_unlock(pmutex);
});
}
NSLog(@"block end");
};
[assetsLibrary enumerateGroupsWithTypes:groupTypes usingBlock:listGroupBlock failureBlock:failureBlock];
pthread_mutex_lock(pmutex);
pthread_mutex_unlock(pmutex);
pthread_mutex_destroy(pmutex);
NSLog(@"queue end");
});
enumerateGroupsWithTypes:usingBlock:failureBlock:
做它的异步工作在另一个线程,并要求当它这样做(在主线程我认为)传入的块。 从另一个角度看它,如果它完成了所有的同步由当时的方法调用完成后,它可能只是返回组的枚举对象,而不是,例如,对于一个简单的API。
从文档:
此方法是异步的。 当组列举,用户可能被要求确认应用程序的数据访问; 该方法,虽然,立即返回。 你应该执行要在enumerationBlock资产力所能及的工作。
我不知道为什么你尝试使用串行队列来完成的,但如果你只是想阻止同时访问,那么你可以只添加一个变量的地方,跟踪我们是否现在正在列举与否和检查起初,如果你不担心同步问题。 (如果你这样做,也许你应该考虑使用GCD组,但它可能是矫枉过正了这种情况。)
我打一个问题是这样,对我来说,答案是认识到,从序列化队列的方法异步调用,去到另一个队列处理 - 一个不序列化。
所以,你必须包装有明确的主要方法内的所有来电dispatch_async(serializedQueue, ^{})
以确保一切都在正确的顺序完成...
你可能有多个对象,每个都有自己的串行队列。 分派到任何一个串行队列任务顺序执行,但分派到不同的串行队列的任务将完全交错。
另一个简单的错误是创建不是串行队列,但并发队列...