Concurrency issue when application goes to on resume


#1

Hello.

I need some help figuring out why my iOS application is crashing due to concurrency issues when my program goes into the the on resume state. Inside the application it is running fine. Do I need to save the manager ID for it to be on the same thread always? or how would I fix it as it is saying the thread is not the same thread started on, and please don’t point me to the documentation for concurrency as it is not helpful.


#2

Are you calling Couchbase Lite from a background thread or dispatch queue? If so, then you need to make another CBLManager to use on that queue. I’m guessing that on wake your app is being called by UIKit and accidentally using the background CBLManager instead of the foreground one.

It would be useful if you could post a backtrace of the thread that gets the error about calling on the wrong thread.


#3

Hello.

I do have a background refresher going in the background which updates the local database, but I have a method in the AppDelegate that creates the manager, creates the databases I need; and when I need to access the database it is called from the app delegate. My issue is that it is returning
***** THREAD-SAFETY VIOLATION: This database is being used on a thread it wasn’t created on! Please see the concurrency guidelines in the Couchbase Lite documentation. *****

when you go back into the app after a while it will throw this error.

Any help or suggestion on this would be great!


#4

Sounds like your app delegate is getting called from a background thread. When you get the exception, look at the thread’s backtrace to see what thread you’re on and how you got there. If you need help, capture a backtrace (type “bt” in the debugger console) and paste it here and I’ll look at it.


#5

Here is the backtrace, appreciate your help

* thread #29: tid = 0x19ebb1, 0x000000011048cf06 libsystem_kernel.dylib`__pthread_kill + 10, queue = 'com.apple.root.default-qos', stop reason = signal SIGABRT
  * frame #0: 0x000000011048cf06 libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x00000001104544ec libsystem_pthread.dylib`pthread_kill + 90
    frame #2: 0x00000001101eecec libsystem_c.dylib`abort + 129
    frame #3: 0x000000010ffed051 libc++abi.dylib`abort_message + 257
    frame #4: 0x0000000110012ac9 libc++abi.dylib`default_terminate_handler() + 267
    frame #5: 0x000000010ec19046 libobjc.A.dylib`_objc_terminate() + 103
    frame #6: 0x000000011001026e libc++abi.dylib`std::__terminate(void (*)()) + 8
    frame #7: 0x00000001100102e3 libc++abi.dylib`std::terminate() + 51
    frame #8: 0x000000010ec18fc5 libobjc.A.dylib`objc_terminate + 9
    frame #9: 0x00000001101143ff libdispatch.dylib`_dispatch_client_callout + 28
    frame #10: 0x00000001100fcb2f libdispatch.dylib`_dispatch_root_queue_drain + 1829
    frame #11: 0x00000001100fc405 libdispatch.dylib`_dispatch_worker_thread3 + 111
    frame #12: 0x00000001104514de libsystem_pthread.dylib`_pthread_wqthread + 1129
    frame #13: 0x000000011044f341 libsystem_pthread.dylib`start_wqthread + 13
(lldb)

#6

Well, that’s an anonymous background thread used by GCD, so it looks like you’re definitely not running on the main thread.

However, the backtrace doesn’t show any CBL or app code, just system stuff, so this must be after the exception’s been thrown. Set an exception breakpoint so you can drop into the debugger when the exception is thrown; that way your code and/or CBL code will be on the stack. (Show the breakpoint navigator, then press the “+” button at the bottom left.)


#7

Heres the stack of the exception when the concurrency issue occurs

*** First throw call stack:
(
0 CoreFoundation 0x000000010f4b1d85 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010ec18deb objc_exception_throw + 48
2 CoreFoundation 0x000000010f4b1bea +[NSException raise:format:arguments:] + 106
3 Foundation 0x000000010be97d5a -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 198
4 app 0x000000010aca751b -[CBL_FMDatabase beginUse] + 155
5 app 0x000000010aca684f -[CBL_FMDatabase executeQuery:withArgumentsInArray:orVAList:] + 200
6 app 0x000000010aca7cf6 -[CBL_FMDatabase(FMDatabaseAdditions) longLongForQuery:] + 160
7 app 0x000000010ac96b22 -[CBL_SQLiteStorage getDocNumericID:] + 129
8 app 0x000000010ac96233 -[CBL_SQLiteStorage getDocumentWithID:revisionID:withBody:status:] + 78
9 app 0x000000010ac7045e -[CBLDatabase(Internal) getDocumentWithID:revisionID:withBody:status:] + 79
10 app 0x000000010ac3bd9c -[CBLDocument currentRevision] + 87
11 app 0x000000010ac3c6b2 -[CBLDocument properties] + 24
12 app 0x000000010a8e3cc2 -[SettingsController getColor:completion:] + 146
13 app 0x000000010a8e323a __58-[SettingsController tableView:cellForRowAtIndexPath:]_block_invoke + 330
14 libdispatch.dylib 0x00000001100f3d9d _dispatch_call_block_and_release + 12
15 libdispatch.dylib 0x00000001101143eb _dispatch_client_callout + 8
16 libdispatch.dylib 0x00000001100fcb2f _dispatch_root_queue_drain + 1829
17 libdispatch.dylib 0x00000001100fc405 _dispatch_worker_thread3 + 111
18 libsystem_pthread.dylib 0x00000001104514de _pthread_wqthread + 1129
19 libsystem_pthread.dylib 0x000000011044f341 start_wqthread + 13
)


#8

OK, it looks like you’ve used dispatch_async or something like that to call your CBL on a background dispatch queue.

But it sounds like you’re normally using CBL on the main thread. If so, you cannot use the same objects on both threads. You have to create a separate CBLManager to use on that dispatch queue.

please don’t point me to the documentation for concurrency as it is not helpful.

Why is it unhelpful? Did you just not understand it?


#9

Ok, I think I’m understanding it now, so I need to create a new manager when in the background basically and when the app goes on resume it’ll have its the other manager basically?


#10

No, it has nothing to do with whether the app is in the background.

CBL objects are (like most Cocoa objects, including Core Data’s) not thread-safe. They can’t be used on multiple threads simultaneously. So if you want to run some of your code on other threads/queues, you have to create a second set of objects (that use the same database file).

Are you experienced with multithreaded programming? If not, it would really be safer to do all of your work on the main thread and not use dispatch queues. (I don’t mean to sound patronizing! But from this thread I get the impression you’re not really aware of the ramifications of running multiple threads/queues.)