簡體   English   中英

為什么主隊列上的GCD dispatch_async會導致后台隊列出現死鎖?

[英]Why does GCD dispatch_async on main queue causes a deadlock from background queue?

我正在創建一個這樣的串行后台隊列:

@property (nonatomic, strong) dispatch_queue_t assetCreationQueue;

// in init...
_assetCreationQueue = dispatch_queue_create("com.mycompany.assetCreationQueue", DISPATCH_QUEUE_SERIAL);

然后我在后台枚舉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];
                });
            }
        });
    }
}];

assets數組屬性定義為:

@property (nonatomic, strong) NSMutableArray *assets;

當我嘗試dispatch_sync(dispatch_get_main_queue(), ^{我只獲得一個NSLog(@"AVURLAsset %@", avAsset);在控制台中它表示dispatch_sync導致死鎖。

但是我怎么能找出原因呢? 我看不到哪里。 assetCreationQueue是后台隊列,我必須僅在主隊列上對陣列進行操作。

編輯:這是一個更簡化的測試,也失敗了:

[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!!
                });
            }
        });
     }
}];

所以我不明白的是:為什么我已經在主線程上,即使我調用dispatch_async(weakSelf.assetCreationQueue 。它只會導致邪惡的結論:我創建的隊列不是后台隊列:

_assetCreationQueue = dispatch_queue_create("com.mycompany.assetCreationQueue", DISPATCH_QUEUE_SERIAL);

為什么?

(不是一個真正的答案,但我想提供足夠的信息來推進。)

我嘗試過一個非常簡單的程序,這根本不會重現。 我接到許多調用“在主隊列上調度異步”並且沒有調用“已經主線程”(與你期望的相反)。 我在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

請注意,在這里使用weakSelf是不必要和危險的(但如果這是問題,你就會崩潰)。 如果weakSelf塊存儲在self保留的對象的屬性中,則只需要weakSelf 對於像這樣的短壽命塊,沒有必要或甚至不需要。 你使用它的方式,如果擁有對象在枚舉的中間釋放(它可以), weakSelf將變為nil, weakSelf.assetCreationQueue將為nildispatch_async()將崩潰。 (但同樣,這不太可能是你的問題的原因,因為它應該崩潰。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM