2013-08-20 24 views
11

La nostra app sembra bloccarsi in modo semi-casuale su psynch_mutexwait. Sembra essere correlato a un processo in background che aggiorna un po 'di dati archiviati in CoreData - ma sono stato completamente incapace di capire chi sta bloccando su cosa causare il deadlock.L'app si blocca su __psynch_mutexwait

Di seguito è riportata la traccia di stack completa fornita da lldb, che è ovviamente incompleta, E l'ultimo frame di Thread 1 è falso. Ho avuto un breakpoint in quel metodo poche righe prima, e non è mai stato colpito.

C'è qualche modo per capire quale blocco è in attesa? (o anche ottenere tracce dello stack corrette?) Ovviamente c'è molto LOTS di codice coinvolto, il che rende le affermazioni di NSLog casuali un impegno enorme.

(lldb) bt all 
* thread #1: tid = 0x2503, 0x39da20fc libsystem_kernel.dylib`__psynch_mutexwait + 24, stop reason = signal SIGSTOP 
    frame #0: 0x39da20fc libsystem_kernel.dylib`__psynch_mutexwait + 24 
    frame #1: 0x39ceb128 libsystem_c.dylib`pthread_mutex_lock + 392 
    frame #2: 0x00022068 OnDeck`-[AttendanceWorkoutsController buildTable](self=0x00000003, _cmd=0x00000000) + 508 at AttendanceWorkoutsController.m:100 

    thread #2: tid = 0x2803, 0x39d92648 libsystem_kernel.dylib`kevent64 + 24 
    frame #0: 0x39d92648 libsystem_kernel.dylib`kevent64 + 24 
    frame #1: 0x39ccb4f0 libdispatch.dylib`_dispatch_mgr_invoke + 796 

    thread #5: tid = 0x2b03, 0x39d91eb4 libsystem_kernel.dylib`mach_msg_trap + 20 
    frame #0: 0x39d91eb4 libsystem_kernel.dylib`mach_msg_trap + 20 
    frame #1: 0x39d9204c libsystem_kernel.dylib`mach_msg + 40 

    thread #6: tid = 0x242f, 0x39d91eb4 libsystem_kernel.dylib`mach_msg_trap + 20 
    frame #0: 0x39d91eb4 libsystem_kernel.dylib`mach_msg_trap + 20 
    frame #1: 0x39d9204c libsystem_kernel.dylib`mach_msg + 40 

    thread #7: tid = 0x2c03, 0x39da2594 libsystem_kernel.dylib`select$DARWIN_EXTSN + 20 
    frame #0: 0x39da2594 libsystem_kernel.dylib`select$DARWIN_EXTSN + 20 
    frame #1: 0x31bff1f6 CoreFoundation`__CFSocketManager + 678 

    thread #8: tid = 0x2d03, 0x39da2d98 libsystem_kernel.dylib`__workq_kernreturn + 8 
    frame #0: 0x39da2d98 libsystem_kernel.dylib`__workq_kernreturn + 8 
    frame #1: 0x39cf0cfa libsystem_c.dylib`_pthread_workq_return + 18 
(lldb) 

risposta

2

Questo ha visto quando un correlata entità in un altro contesto (e su un altro thread) è stata modificata ma non sono ancora persistenti.

Lo scenario:

A --> B

causa di un bug B era in attesa di cambiamenti, in un altro contesto, su un altro thread. Il bug ha causato il blocco dello B invece del salvataggio o del rollback. Se si tenta di salvare A nel contesto/thread corrente, si attenderà che l'altro thread rilasci il blocco su B.

Solo un modo efficace per risolvere i problemi era elencare tutte le entità in sospeso e confrontarle con quelle nel thread bloccato. Ha preso un po ':(

Sto ancora cercando qualcosa che elencare tutte le serrature sul database ed entità.

12

Avendo molte persone guardano il codice, e tracciano attraverso i percorsi di codice lungo complicate, abbiamo trovato quello sembra essere stato il colpevole. un metodo in esecuzione in un thread in background era trovare e utilizzare alcuni oggetti core Data e utilizzando il contesto principale-thread.

Certo avrebbe aiutato molto se IOS darebbe stack utili.

+2

provare ad abilitare dati fondamentali multithread innescare affermazioni. È stato introdotto per queste situazioni. – Mazyod

2

Ciò accade solitamente quando si tenta di accedere a Core Oggetti dati su un thread in background utilizzando il contesto di thread principali O utilizzando lo stesso contesto dell'oggetto gestito su thread diversi (background o main) allo stesso tempo. Per ulteriori dettagli, consulta Core Data concurrency rules.

Quindi, per evitare entrambi i casi, la regola principale è che ogni thread deve avere il proprio contesto di oggetto gestito e inizializzare quel contesto esattamente dove verrà utilizzato.

Ad esempio:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 

    // 
    // Prepare your background core data context 
    // 

    if (self.privateContext == nil) 
    { 
     self.privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
     [self.privateContext setParentContext: - main managed object context - ]; 
     [self.privateContext setUndoManager:nil]; // this context should not manage undo actions. 
    } 

    // 
    // Do any Core Data requests using this thread-save context 
    // 

    . 
    . 
    . 

});