2012-04-21 15 views
8

Tôi đang dispatch_sync() 'ing một khối trên hàng đợi chính. Trong khối này, một cuộc gọi đến executeFetchRequest:error: cuối cùng được thực hiện. Đôi khi, điều này gây ra một bế tắc.Khóa liên kết giữa dispatch_sync trên hàng đợi chính và executeFetchRequest: lỗi:

Dưới đây là bài viết 1 trong đó cho thấy khối gọi vào các chủ đề chính và sau đó là cuộc gọi đến executeFetchRequest:error:

#0 0x981f3876 in __psynch_mutexwait() 
#1 0x97a016af in pthread_mutex_lock() 
#2 0x0135be32 in -[_PFLock lock]() 
#3 0x0135be0a in -[NSPersistentStoreCoordinator lock]() 
#4 0x01371d1c in -[NSManagedObjectContext(_NSInternalAdditions) lockObjectStore]() 
#5 0x013702c0 in -[NSManagedObjectContext executeFetchRequest:error:]() 
#6 0x0000a701 in -[NSManagedObjectContext(Convenience) fetchObjectsForEntityName:onlyIDs:withPredicate:] at /Users/mike/Dropbox/src/Tracky-iPhone/Tracky/Tracky/NSManagedObjectContext(Convenience).m:50 
#7 0x00065270 in +[NSManagedObject(ContextAdditions) contextForID:managedObjectContext:] at /Users/mike/Dropbox/src/Tracky-iPhone/Tracky/Tracky/NSManagedObject+ContextAdditions.m:40 
#8 0x0006597e in __85+[NSManagedObject(ContextAdditions) createContextIfNeededForID:managedObjectContext:]_block_invoke_0 at /Users/mike/Dropbox/src/Tracky-iPhone/Tracky/Tracky/NSManagedObject+ContextAdditions.m:55 
#9 0x00065aad in __85+[NSManagedObject(ContextAdditions) createContextIfNeededForID:managedObjectContext:]_block_invoke_050 at /Users/mike/Dropbox/src/Tracky-iPhone/Tracky/Tracky/NSManagedObject+ContextAdditions.m:64 
#10 0x023cf8d9 in _dispatch_barrier_sync_f_slow_invoke() 
#11 0x023d0509 in _dispatch_main_queue_callback_4CF() 
#12 0x01ae9803 in __CFRunLoopRun() 
#13 0x01ae8d84 in CFRunLoopRunSpecific() 
#14 0x01ae8c9b in CFRunLoopRunInMode() 
#15 0x019b47d8 in GSEventRunModal() 
#16 0x019b488a in GSEventRun() 
#17 0x004ba626 in UIApplicationMain() 

Tôi có thể thấy rằng executeFetchRequest:error: chặn trên khóa NSPersistentStoreCoordinator 's, nhưng tôi không biết ai hiện tại đã bị khóa.

Bản gốc dispatch_sync() đang xảy ra từ một sợi khác nhau, và đây là rằng trong trường hợp điều quan trọng là:

Thread 18, Queue : (null) 
#0 0x981f1c5e in semaphore_wait_trap() 
#1 0x023d1bda in _dispatch_thread_semaphore_wait() 
#2 0x023d0cb2 in _dispatch_barrier_sync_f_slow() 
#3 0x023d0e0f in dispatch_barrier_sync_f() 
#4 0x023d0f4c in _dispatch_sync_slow() 
#5 0x0006563a in +[NSManagedObject(ContextAdditions) createContextIfNeededForID:managedObjectContext:] at /Users/mike/Dropbox/src/Tracky-iPhone/Tracky/Tracky/NSManagedObject+ContextAdditions.m:63 
#6 0x0006e2ee in __109-[ItemFetcher createOrConfigureObjectWithDescriptor:withContext:jsonObjectIDKey:modelObjectIDKey:entityName:]_block_invoke_0 at /Users/mike/Dropbox/src/Tracky-iPhone/Tracky/Tracky/ItemFetcher.m:78 
#7 0x023ce330 in _dispatch_call_block_and_release() 
#8 0x023cff0c in _dispatch_queue_drain() 
#9 0x023cfcb4 in _dispatch_queue_invoke() 
#10 0x023cf402 in _dispatch_worker_thread2() 
#11 0x97a04b24 in _pthread_wqthread() 

Đây là mã lên đến văn bản gốc:

+ (Context *) createContextIfNeededForID: (NSString *) contextID managedObjectContext:(NSManagedObjectContext *) moc 
    { 
    // See if this context is in the main MOC. This call needs to happen synchronously on the main queue, if we're 
    // not on the main queue 
    Context * (^contextFromMainMOCBlock)(void) = 
     ^`Context` * { 
     // We are guaranteed to be in the main here; look at how this block is invoked. 
     return [self contextForID:contextID managedObjectContext:[UIApplication trackyAppDelegate].managedObjectContext] ; 
     } ; 

    __block Context *contextFromMainMOC = nil ; 

    if([UIApplication trackyAppDelegate].managedObjectContext == moc) 
     contextFromMainMOC = contextFromMainMOCBlock() ; 
    else 
     dispatch_sync(dispatch_get_main_queue(), ^{ 
      contextFromMainMOC = contextFromMainMOCBlock() ; // <-- here 
      }) ; 
… 

contextForID:contextID managedObjectContext: thực sự doesn' t làm bất cứ điều gì với dữ liệu cốt lõi cho đến khi nó gọi executeFetchRequest:error:.

CẬP NHẬT

Dưới đây là phần còn lại của dấu vết ngăn xếp. AFAIK họ không làm bất cứ điều gì thú vị mặc dù tôi có thể sai.

Thread 3, Queue : (null) 
#0 0x981f490a in kevent() 
#1 0x023d0372 in _dispatch_mgr_invoke() 
#2 0x023cebe1 in _dispatch_mgr_thread() 
Thread 5 WebThread, Queue : (null) 
#0 0x981f1c22 in mach_msg_trap() 
#1 0x981f11f6 in mach_msg() 
#2 0x01b8610a in __CFRunLoopServiceMachPort() 
#3 0x01ae95d5 in __CFRunLoopRun() 
#4 0x01ae8d84 in CFRunLoopRunSpecific() 
#5 0x01ae8c9b in CFRunLoopRunInMode() 
#6 0x04776420 in _ZL12RunWebThreadPv() 
#7 0x97a02ed9 in _pthread_start() 
Thread 6 com.apple.NSURLConnectionLoader, Queue : (null) 
#0 0x981f1c22 in mach_msg_trap() 
#1 0x981f11f6 in mach_msg() 
#2 0x01b8610a in __CFRunLoopServiceMachPort() 
#3 0x01ae95d5 in __CFRunLoopRun() 
#4 0x01ae8d84 in CFRunLoopRunSpecific() 
#5 0x01ae8c9b in CFRunLoopRunInMode() 
#6 0x00ebae30 in +[NSURLConnection(Loader) _resourceLoadLoop:]() 
#7 0x00dcc4d6 in -[NSThread main]() 
#8 0x00dcc447 in __NSThread__main__() 
#9 0x97a02ed9 in _pthread_start() 
Thread 10 com.apple.CFSocket.private, Queue : (null) 
#0 0x981f3b42 in select$DARWIN_EXTSN() 
#1 0x01b1a7cb in __CFSocketManager() 
#2 0x97a02ed9 in _pthread_start() 

Và đây là contextID:managedObjectContext: đó là phương pháp gọi trong dispatch_sync():

+ (Context *) contextForID: (NSString *) contextID managedObjectContext:(NSManagedObjectContext *) moc 
    { 
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"cid == %@", contextID] ; 
    NSSet *contexts = [moc fetchObjectsForEntityName:@"Context" onlyIDs:NO withPredicate:predicate] ; 

    // Integrity check 
    NSAssert1(contexts.count < 2, @"More than one context with the same CID exists: %@" , contexts) ; 

    return [contexts anyObject] ; 
    } 

fetchObjectsForEntityName:onlyIDs:withPredicate: trông như thế này:

- (NSSet *)fetchObjectsForEntityName:(NSString *)newEntityName onlyIDs: (BOOL) onlyIDs 
    withPredicate:(id)stringOrPredicate, ... 
    { 
    NSEntityDescription *entity = [NSEntityDescription 
     entityForName:newEntityName inManagedObjectContext:self]; 

    NSAssert1(entity != nil , @"entity not found for \"%@\"" , newEntityName) ; 

    NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
    [request setEntity:entity]; 
    [request setIncludesPropertyValues:!onlyIDs] ; 

    if (stringOrPredicate) 
     { 
     NSPredicate *predicate; 
     if ([stringOrPredicate isKindOfClass:[NSString class]]) 
      { 
      va_list variadicArguments; 
      va_start(variadicArguments, stringOrPredicate); 
      predicate = [NSPredicate predicateWithFormat:stringOrPredicate 
       arguments:variadicArguments]; 
      va_end(variadicArguments); 
      } 
     else 
      { 
      NSAssert2([stringOrPredicate isKindOfClass:[NSPredicate class]], 
       @"Second parameter passed to %s is of unexpected class %@", 
       sel_getName(_cmd), NSStringFromClass(stringOrPredicate)); 
      predicate = (NSPredicate *)stringOrPredicate; 
      } 
     [request setPredicate:predicate]; 
     } 

    NSError *error = nil; 
    NSArray *results ; 
    @try { 
     results = [self executeFetchRequest:request error:&error]; 
    } 
    @catch (NSException *exception) { 
     NSLog(@"Exception caught: %@" , exception) ; 
    } 

    if (error != nil) 
     { 
     [NSException raise:NSGenericException format:@"%@",[error description]]; 
     } 

    return [NSSet setWithArray:results]; 
    } 
+4

Hãy thử 'dispatch_async() 'sau đó mã này sẽ không ngồi chờ đợi –

+1

là những chủ đề khác làm gì vậy? Ngoài ra, tôi đồng ý với Paul.s một chút. Triết lý của GCD là bạn nên tránh công văn đồng bộ bất cứ khi nào bạn có thể. Vấn đề là bạn đã thiết kế một API trả về dữ liệu cho người gọi của nó mà sau đó hành động trên đó, vì vậy nó phải được đồng bộ. Thay vào đó, phải có một khối để xử lý dữ liệu khi nó có sẵn. Người gọi có thể vượt qua điều đó, cho phép toàn bộ hoạt động không đồng bộ. –

+0

Tôi đồng ý với cả hai bạn.Mã này ban đầu được viết mà không có khối và GCD, và nếu điều này làm việc nó sẽ giữ hầu hết các giao diện còn nguyên vẹn. Nhưng có lẽ nó sẽ mất một refactor lớn. Vui vẻ. – leftspin

Trả lời

0

Để cung cấp sự giúp đỡ nhiều hơn, bạn cần phải chứng minh mã cho tất cả các phương pháp trong dấu vết ngăn xếp, cùng với số dòng. Bằng cách đó, nó có thể được tương quan.

Ngoài ra, có vẻ như bạn có nhiều chủ đề. Tôi nghĩ bạn sẽ phải kiểm tra những người khác để xem điều gì đang xảy ra.

Bạn phải rất cẩn thận khi gọi một hoạt động đồng bộ hóa, đặc biệt nếu nó có thể được gọi từ các hoạt động đồng bộ khác.

0

Kiểm tra NSManagedObjectContext cho concurrencyType của bạn. Dường như ngữ cảnh của bạn có NSMainQueueConcurrencyType, chạy tất cả các yêu cầu trong chuỗi chính. Từ Apple reference:

NSMainQueueConcurrencyType

Specifies that the context will be associated with the main queue.

Nếu tôi đúng bạn cần phải thay đổi loại để NSPrivateQueueConcurrencyType

Các vấn đề liên quan