Main aspect of the question: It's about iOS. Can I somehow dispatch code blocks in a way, that they will all (a) run in background and (b) on the same thread? I want to run some time-consuming operations in background, but these have to be run on the same thread, because they involve resources, that mustn't be shared among threads.
Further technical details, if required: It's about implementing an sqlite plugin for Apache Cordova, a framework for HTML5 apps on mobile platforms. This plugin should be an implementation of WebSQL in the means of the Cordova's plugin API. (That means, it's not possible to wrap entire transactions within single blocks, what could make everything easier.)
Here is some code from Cordova's Docs:
- (void)myPluginMethod:(CDVInvokedUrlCommand*)command
{
// Check command.arguments here.
[self.commandDelegate runInBackground:^{
NSString* payload = nil;
// Some blocking logic...
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:payload];
// The sendPluginResult method is thread-safe.
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}];
}
But as far as I know, there is no guarantee, that those dispatched code blocks (see runInBackground
) will run on the same thread.
You can either use
NSOperationQueue
with aMaxConcurrentOperationCount
of1
or go the manual way down the road by usingNSThread
model (rather than Grand Central Dispatch). Using the latter I would recommend you to implement a worker-method which runs in a thread and pulls work-packages (or commands) from a queue or a pool that is being feed from outside of the thread. Just make sure you use Locks / Mutex / Synchronisation.Just like this,
Create a serial dispatch queue, and dispatch all the calls to that serial dispatch queue. All the calls will be performed in the background, but sequentially on the same thread.
GCD makes no guarantee that two blocks run on the same thread, even if they belong to the same queue (with the exception of the main queue, of course). However, if you're using a serial queue (
DISPATCH_QUEUE_SERIAL
) this isn't a problem as you then know that there is no concurrent access to your data.The man page for
dispatch_queue_create
says:I'm not aware of any way to bind a queue to a specific thread (after all, not needing to care about threads is a major point of GCD). The reason why you can use a serial queue without worrying about the actual thread is this promise:
That is, a memory barrier seems to be used.
When dealing with threading issues, your main concern is usually to avoid that two threads access something concurrently. If you're using a serial queue you do not have this problem. It usually doesn't really matter which thread is accessing your resources. For example, we're using serial queues to manage Core Data access without a problem.
Edit:
It seems you really found a rare case where you need to be working on the same thread. You could implement your own worker thread:
blockQueue
).queueCondition
).Due to the condition, the thread will simply sleep while there's no work to do.
So, roughly (untested, assuming ARC):
You can use
NSOperationQueue
. You can make it use just one thread by using method- (void)setMaxConcurrentOperationCount:(NSInteger)count
. Set it to 1Never tried this but this might do the trick. Use separate properties of
atomic
dispatch queues for each operation.Queue/Thread 1 for first operation
etc.
Since
atomic
is thread safe,downloadQueue
should not be accessed by other threads. So it makes sure that there will be only single thread per operation and other threads will not access it.