[英]Why does GCD dispatch_async on main queue causes a deadlock from background queue?
I am creating a serial background queue like this: 我正在创建一个这样的串行后台队列:
@property (nonatomic, strong) dispatch_queue_t assetCreationQueue;
// in init...
_assetCreationQueue = dispatch_queue_create("com.mycompany.assetCreationQueue", DISPATCH_QUEUE_SERIAL);
Then I enumerate ALAsset objects in the background like this: 然后我在后台枚举ALAsset对象,如下所示:
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop){
if (asset){
dispatch_async(weakSelf.assetCreationQueue, ^{
ALAssetRepresentation *assetRepresentation = [asset defaultRepresentation];
NSURL *url = [assetRepresentation url];
if (url) {
AVURLAsset *avAsset = [[AVURLAsset alloc] initWithURL:url options:nil];
// This NSLog fires! avAsset exists.
NSLog(@"AVURLAsset %@", avAsset);
dispatch_async(dispatch_get_main_queue(), ^{
// This NSLog NEVER fires.
// Also tried dispatch_sync.
NSLog(@"add to assets array on main queue");
[weakSelf.assets insertObject:avAsset atIndex:0];
});
}
});
}
}];
The assets array property is defined as: assets数组属性定义为:
@property (nonatomic, strong) NSMutableArray *assets;
When I try dispatch_sync(dispatch_get_main_queue(), ^{
I only get ONE NSLog(@"AVURLAsset %@", avAsset);
in the console and it indicates that dispatch_sync
is causing a deadlock. 当我尝试
dispatch_sync(dispatch_get_main_queue(), ^{
我只获得一个NSLog(@"AVURLAsset %@", avAsset);
在控制台中它表示dispatch_sync
导致死锁。
But how can I find out why? 但是我怎么能找出原因呢? I don't see where.
我看不到哪里。 The assetCreationQueue is a background queue and I have to operate on the array only on the main queue.
assetCreationQueue是后台队列,我必须仅在主队列上对阵列进行操作。
EDIT: Here is a much more simplified test which also fails: 编辑:这是一个更简化的测试,也失败了:
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop){
if (asset){
dispatch_async(weakSelf.assetCreationQueue, ^{
if ([NSThread isMainThread]) {
NSLog(@"already main thread"); // gets called often!!
} else {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"dispatch async on main queue"); // never gets called!!
});
}
});
}
}];
So what I don't understand is: Why am I already on the main thread even though I call dispatch_async(weakSelf.assetCreationQueue
. It can only lead to evil conclusion: The queue I create is NOT a background queue: 所以我不明白的是:为什么我已经在主线程上,即使我调用
dispatch_async(weakSelf.assetCreationQueue
。它只会导致邪恶的结论:我创建的队列不是后台队列:
_assetCreationQueue = dispatch_queue_create("com.mycompany.assetCreationQueue", DISPATCH_QUEUE_SERIAL);
Why? 为什么?
(Not really an answer, but I want to provide enough information to move forward.) (不是一个真正的答案,但我想提供足够的信息来推进。)
I've tried a very simple program, and this doesn't reproduce at all. 我尝试过一个非常简单的程序,这根本不会重现。 I get many calls to "dispatch async on main queue" and no calls to "already main thread" (the opposite of what you're expecting).
我接到许多调用“在主队列上调度异步”并且没有调用“已经主线程”(与你期望的相反)。 I'm running this on an iPhone 5. Complete code:
我在iPhone 5上运行它。完整的代码:
#import "AppDelegate.h"
@import AssetsLibrary;
@interface AppDelegate ()
@property (nonatomic, strong) dispatch_queue_t assetCreationQueue;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.assetCreationQueue = dispatch_queue_create("com.mycompany.assetCreationQueue", DISPATCH_QUEUE_SERIAL);
ALAssetsLibrary* library = [[ALAssetsLibrary alloc] init];
AppDelegate __weak *weakSelf = self;
[library enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop){
if (asset){
dispatch_async(weakSelf.assetCreationQueue, ^{
if ([NSThread isMainThread]) {
NSLog(@"already main thread"); // gets called often!!
} else {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"dispatch async on main queue"); // never gets called!!
});
}
});
}
}];
}
failureBlock:nil];
return YES;
}
@end
Note that the use of weakSelf
here is unnecessary and dangerous (but if this were the problem, you'd be crashing). 请注意,在这里使用
weakSelf
是不必要和危险的(但如果这是问题,你就会崩溃)。 You only need weakSelf
if the block is going to be stored in a property of an object that self
retains. 如果
weakSelf
块存储在self
保留的对象的属性中,则只需要weakSelf
。 It is not necessary or even desired for short-lived blocks like this. 对于像这样的短寿命块,没有必要或甚至不需要。 The way you've used it, if the owning object deallocated in the middle of the enumeration (which it can),
weakSelf
would become nil, weakSelf.assetCreationQueue
would be nil
, and dispatch_async()
would crash. 你使用它的方式,如果拥有对象在枚举的中间释放(它可以),
weakSelf
将变为nil, weakSelf.assetCreationQueue
将为nil
, dispatch_async()
将崩溃。 (But again, this is unlikely the cause of your issue, since it should crash.) (但同样,这不太可能是你的问题的原因,因为它应该崩溃。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.