Using an application-lifetime-thread other than the main thread - iphone

I've a multi-threading application in which each thread has to do some job, but at a certain point some code needs to be executed serially (like writing into sqlite3 database), so I'm calling that code to be performed on main thread using:
[self performSelectorOnMainThread:#selector(serialJob:) withObject:object waitUntilDone:YES];
and every thing went just fine except that when that code needs some time the user interaction with the application gets disabled until that code has been finished, so is there any way to make another ONE thread that can be run on background and can be called whenever I need it just like the main one so I can replace the previous call with:
[self performSelector:#selector(serialJob:) onThread:REQUIRED_THREAD withObject:object waitUntilDone:YES];
this thread should be some class's static data member to be accessed from all over the code.
any help would be very appreciated, and many thanks in advance...

This is quite easy to do, just spawn your thread and let it run it's runloop using [[NSRunLoop currentRunLoop] run]. That's all that is required to be able to use performSelector:onThread: with a custom thread.
If you are on iOS 4 or newer you should consider using Grand Central Dispatch queues instead of threads though. The GCD APIs are much easier to use and can utilize the system resources much better.

Like Sven mentioned, look into Grand Central Dispatch.
You can create a queue like this:
dispatch_queue_t myQueue = dispatch_queue_create("com.yourcompany.myDataQueue", NULL);
Now you can call blocks on that queue:
dispatch_async(myQueue, ^{
// Your code to write to DB.
});
When you're done, don't forget to release the queue:
dispatch_release(myQueue);

Due to the my question that I need the current thread to be blocked until the database job has been finished, I've tried these two solutions and they worked perfectly. You can either use critical sections or NSOperationQueue and I prefer the first one, here is the code for both of them:
define some class "DatabaseController" and add this code to its implementation:
static NSString * DatabaseLock = nil;
+ (void)initialize {
[super initialize];
DatabaseLock = [[NSString alloc] initWithString:#"Database-Lock"];
}
+ (NSString *)databaseLock {
return DatabaseLock;
}
- (void)writeToDatabase1 {
#synchronized ([DatabaseController databaseLock]) {
// Code that writes to an sqlite3 database goes here...
}
}
- (void)writeToDatabase2 {
#synchronized ([DatabaseController databaseLock]) {
// Code that writes to an sqlite3 database goes here...
}
}
OR to use the NSOperationQueue you can use:
static NSOperationQueue * DatabaseQueue = nil;
+ (void)initialize {
[super initialize];
DatabaseQueue = [[NSOperationQueue alloc] init];
[DatabaseQueue setMaxConcurrentOperationCount:1];
}
+ (NSOperationQueue *)databaseQueue {
return DatabaseQueue;
}
- (void)writeToDatabase {
NSInvocationOperation * operation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(FUNCTION_THAT_WRITES_TO_DATABASE) object:nil];
[operation setQueuePriority:NSOperationQueuePriorityHigh];
[[DatabaseController databaseQueue] addOperations:[NSArray arrayWithObject:operation] waitUntilFinished:YES];
[operation release];
}
these two solutions block the current thread until the writing to database is finished which you may consider in most of the cases.

Related

What is preferred: implement method with GCD inside and then just simple call, or implement method and then call it later with GCD?

what's is more prefered way to write multi threaded apps. I see two ways.
Implement method with GCD inside and then just simple call (myMethodA), or just implement method and then call it with GCD? Thanks in advance.
My point:
ClassA / method implementation
- (void)myMethodA
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// doSomething1
// doSomething2
});
}
- (void)myMethodB
{
// doSomething1
// doSomething2
}
ClassB / method call
{
[myClassA methodA];
// or
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[myClassA methodB];
};
}
IMHO, neither.
The preferred way should be having an object which knowns where to execute its actions:
completion_block_t completionHandler = ^(id result) { ... };
AsyncOperation* op = [AsyncOperation alloc] initWithCompletion:completionHandler];
[op start]; // executes its actions on a private execution context
Then, one can wrap those AsyncOperation objects into a convenient method:
- (void) fetchUsersWithCompletion:(completion_block_t)completionHandler
{
NSDictionary* params = ...;
self.currentOperation = [[HTTPOperation alloc] initWithParams:params
completion:completionHandler];
[self.currentOperation start];
}
The client may only be interested in specifying where its completionHandler should be executed. The API may be enhanced as follows:
- (void) fetchUsersWithQueue:(NSOperationQueue*)handlerQueue
withCompletion:(completion_block_t)completionHandler
{
NSDictionary* params = ...;
self.currentOperation = [[HTTPOperation alloc] initWithParams:params
completion:^(id result){
// As per the documentation of HTTPOperation, the handler will be executed
// on an _unspecified_ execution context.
// Ensure to execute the client's handler on the specified operation queue:
[handlerQueue:addOperationWithBlock:^{
completionHandler(result);
}];
}];
[self.currentOperation start];
}
The latter API can be used as this:
[self fetchUsersWithQueue:[NSOperation mainQueue] completion:^(id result){
self.users = result;
[self.tableView reloadData];
}];
Personal preference. Choose whichever makes the code more readable / understandable / obvious. Also, consideration of whether the code should be possible to run on the 'current' thread or whether it should always be run on a background thread. You need to design your threading configuration, describe it and then implement with that in mind. If you're calling methods between classes like in your example then I'd generally say that any threading should be handled inside that class, not inside the calling class. But that's about distribution of knowledge.
It doesn't make much of a difference - it just depends on what you want to do.
If you want to execute the method on different queues each time, then the myMethodB system is more appropriate. If, however, you always want to run the method on the same queue, then myMethodA will save you time writing code (you only have to write the GCD code once).

Dispatch queues, concurrency and completion handling

I have an array of objects to be processed. The objects have a method like below
#interface CustomObject : NSObject
- (void)processWithCompletionBlock:(void (^)(BOOL success))completionBlock;
#end
The processing of each object takes various time and can have different results. And it is known that the processing itself is executing concurrently. To say the truth it would be great to limit the number of concurrent operations because they are pretty intensive.
So I need to enumerate this array of objects and process them. If some object processing fails I need to skip all the rest objects. And of course I need to be notified after all objects will be enumerated and processed.
Should it be solved by the creation of NSOperationQueue and NSOperation subclass? How this class could look to fulfill these requirements? Are there some other elegant approaches?
This is exactly what NSOperation is designed for. Dispatch queues are much lower-level handlers, and you'd have to construct many of the pieces you need for this. You can of course do that (NSOperationQueue is built on top of GCD), but you'd be reinventing NSOperation.
You can handle NSOperation two ways for the most part. If it's simple, you can just create an NSBlockOperation. If it's a bit more complex, you can subclass NSOperation and override the main method to do what you want.
There are several ways to cancel all the other operations. You could have a separate operation queue per group. Then you can easily call cancelAllOperations to shut down everything. Or you could have a separate controller that knows the list of related operations and it could call cancel on them.
Remember that "cancel" just means "don't schedule if it hasn't stared, and set isCancelled if it has." It doesn't abort a running operation. If you want to abort a running operation, the operation needs to periodically check isCancelled.
You typically should limit the number of concurrent operations the queue will run. Use setMaximimumConcurrentOperationCount:.
There are two ways to determine that all the operations are finished. You can make an extra operation (usually a BlockOperation) and use addDependency: to make it depend on all the other operations. That's a nice asynchronous solution. If you can handle a synchronous solution, then you can use waitUntilAllOperationsAreFinished. I typically prefer the former.
Use NSOperationQueue and make your Class an NSOperation
Use this method to queue your work
- (void)addOperations:(NSArray *)ops waitUntilFinished:(BOOL)wait
Add a reference to the operation queue to the NSOperation subclass you create
If an error occurs call
- (void)setSuspended:(BOOL)suspend
on NSOperationQueue
Ok. To help others to understand how this approach can be handled I am sharing my own code.
To limit the number of concurrent threads we can call the -(void)setMaximimumConcurrentOperationCount: method of NSOperationQueue instance.
To iterate objects and provide the completion mechanism we can define the following method:
- (void)enumerateObjects:(NSArray *)objects
{
// define the completion block
NSBlockOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(#"Update UI");
}];
// register dependencies
for (CustomObject *obj in objects) {
CustomOperation *operation = [[CustomOperation alloc] initWithCustomObject:obj];
[completionOperation addDependency:operation]; // set dependencies for the completion block
[_operationQueue addOperation:operation];
}
// register completionOperation on main queue to avoid the cancellation
[[NSOperationQueue mainQueue] addOperation:completionOperation];
}
Overwrite the - (void)start method of the NSOperation subclass to start our custom operation:
- (void)start
{
// We need access to the operation queue for canceling other operations if the process fails
_operationQueue = [NSOperationQueue currentQueue];
if ([self isCancelled]) {
// Must move the operation to the finished state if it is canceled.
[self willChangeValueForKey:#"isFinished"];
_finished = YES;
[self didChangeValueForKey:#"isFinished"];
return;
}
[self willChangeValueForKey:#"isExecuting"];
// We do not need thread detaching because our `-(void)processWithCompletionBlock:` method already uses dispatch_async
[self main]; // [NSThread detachNewThreadSelector:#selector(main) toTarget:self withObject:nil];
_executing = YES;
[self didChangeValueForKey:#"isExecuting"];
}
Overwrite the - (void)main method of the NSOperation subclass to process our custom object:
- (void)main
{
#try {
NSLog(#"Processing object %#", _customObject);
[_customObject processWithCompletionBlock:^(BOOL success) {
_processed = success;
if (!success) {
NSLog(#"Cancelling other operations");
[_operationQueue cancelAllOperations];
}
[self completeOperation];
}];
}
#catch (NSException *exception) {
NSLog(#"Exception raised, %#", exception);
}
}
Thanx to #Rob for pointing me out to the missing part.

store data in database in background using multi-threading for iPhone [duplicate]

I have an iPhone app that is using sqlite 3.6 (not with FMDB) to store and load data. I load the database when the app loads and uses the same database connection through the whole app.
In a background thread the app downloads some data from a webserver and writes to the database. At the same time the main thread also might need to write to the same database. This sometimes leads to EXC_BAD_ACCESS as both threads are trying to access the database.
What is the best and easiest way to be able to use the database from different threads?
This is an example that shows the problem:
sqlite3 *database;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"database.db"];
if (sqlite3_open([path UTF8String], &database) != SQLITE_OK) {
sqlite3_close(database);
return YES;
}
[NSThread detachNewThreadSelector:#selector(test) toTarget:self withObject:nil];
[self test];
return YES;
}
-(void)test {
for (int i = 0; i < 2000; i++) {
NSLog(#"%i",i);
sqlite3_exec([self getDb],"UPDATE mytable SET test=''", 0, 0, 0);
}
}
EDIT:
After willcodejavaforfood's answer below I've tried to change my code to use a separate database object (connection) for each separate thread and also added sqlite3_busy_timeout() so that sqlite will retry to write if the database is busy. Now I don't get EXC_BAD_ACCESS anymore but I've noticed that not all data get inserted. So this is not a stable solution either. It seems to be really hard to get sqlite working with threading..
My new solution with separate connections:
-(void)test {
sqlite3 *db = [self getNewDb];
for (int i = 0; i < 2000; i++) {
NSLog(#"%i",i);
sqlite3_exec(db,"UPDATE mytable SET test=''", 0, 0, 0);
}
}
- (sqlite3 *)getNewDb {
sqlite3 *newDb = nil;
if (sqlite3_open([[self getDbPath] UTF8String], &newDb) == SQLITE_OK) {
sqlite3_busy_timeout(newDb, 1000);
} else {
sqlite3_close(newDb);
}
return newDb;
}
I solved this problem by using one thread and an NSOperationQueue to insert the Data. I would give it some thought. I've never been able to get a stable System with mutliple threads, and most writes aren't that important that queuing really helps.
As per request, some more Infos:
I have a subclass of NSOperation that I instantiate with the model object I want to store.
These operations are than submitted to an extension of NSOperationsQueue that runs in a seperate thread. This custom Queue just adds a pointer to the database instance. When the operation is executed, it uses the [NSOperationsQueue currentQueue] property to access the queue and than the database. On purpose, i used non-concurrent operations (maxOperations was set to 1)
Hence, only one query (or update) is executed at a time consecutivly, completely in the background.
Obviously you need some kind of callback after you're finished.
It is possibly not the fast, but the most stable and cleanest solution i could find.
Docs:
http://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationObjects/OperationObjects.html
http://www.cimgf.com/2008/02/16/cocoa-tutorial-nsoperation-and-nsoperationqueue/
http://icodeblog.com/2010/03/04/iphone-coding-turbo-charging-your-apps-with-nsoperation/
As you've noticed only one thread can access an sqlite database at a time. Options to prevent simultaneous access:
Create a new database connection in each thread and rely on file locking (costly).
Turn on sqlite3_config(SQLITE_CONFIG_SERIALIZED).
Use NSLock's.
Use GCD (Grand Central Dispatch) queue's.
The first three options may cause busy waiting (one thread waiting on another to release the lock) which is wasteful.
I use option 4 because it simplifies the task of creating new queries to run in the background and has no busy waiting. It also makes sure all queries execute in the order they were added (which my code tends to assume).
dispatch_queue_t _queue = dispatch_queue_create("com.mycompany.myqueue", DISPATCH_QUEUE_SERIAL);
// Run a query in the background.
dispatch_async(_queue, ^{
...some query
// Perhaps call a completion block on the main thread when done?
dispatch_async(dispatch_get_main_queue(), ^{
//completion(results, error);
});
});
// Run a query and wait for the result.
// This will block until all previous queries have finished.
// Note that you shouldn't do this in production code but it may
// be useful to retrofit old (blocking) code.
__block NSArray *results;
dispatch_sync(_queue, ^{
results = ...
});
...use the results
dispatch_release(_queue);
In a perfect world sqlite would let you perform simultaneous reads but only one write at a time (eg. like using dispatch_barrier_async() for writes and dispatch_async() for reads).
This is all explained in the Core Data Programming Guide in the section for Concurrency.
The pattern recommended for concurrent
programming with Core Data is thread
confinement.
You should give each thread its own
entirely private managed object
context and keep their associated
object graphs separated on a
per-thread basis.
There are two possible ways to adopt
the pattern:
Create a separate managed object
context for each thread and share a
single persistent store coordinator.
This is the typically-recommended
approach.
Create a separate managed object
context and persistent store
coordinator for each thread. This
approach provides for greater
concurrency at the expense of greater
complexity (particularly if you need
to communicate changes between
different contexts) and increased
memory usage.
I've tried these two solutions and they worked perfectly. You can either use critical sections or NSOperationQueue and I prefer the first one, here is the code for both of them:
define some class "DatabaseController" and add this code to its implementation:
static NSString * DatabaseLock = nil;
+ (void)initialize {
[super initialize];
DatabaseLock = [[NSString alloc] initWithString:#"Database-Lock"];
}
+ (NSString *)databaseLock {
return DatabaseLock;
}
- (void)writeToDatabase1 {
#synchronized ([DatabaseController databaseLock]) {
// Code that writes to an sqlite3 database goes here...
}
}
- (void)writeToDatabase2 {
#synchronized ([DatabaseController databaseLock]) {
// Code that writes to an sqlite3 database goes here...
}
}
OR to use the NSOperationQueue you can use:
static NSOperationQueue * DatabaseQueue = nil;
+ (void)initialize {
[super initialize];
DatabaseQueue = [[NSOperationQueue alloc] init];
[DatabaseQueue setMaxConcurrentOperationCount:1];
}
+ (NSOperationQueue *)databaseQueue {
return DatabaseQueue;
}
- (void)writeToDatabase {
NSInvocationOperation * operation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(FUNCTION_THAT_WRITES_TO_DATABASE) object:nil];
[operation setQueuePriority:NSOperationQueuePriorityHigh];
[[DatabaseController databaseQueue] addOperations:[NSArray arrayWithObject:operation] waitUntilFinished:YES];
[operation release];
}
these two solutions block the current thread until the writing to database is finished which you may consider in most of the cases.

Using AsyncSocket with secondary threads on the iPhone

I use AsyncSocket on the iPhone to communicate with a server. AsyncSocket is based on run loops but my app is based on threads. That means, I start a new thread to write data and wait until a response is received on the same thread. But I can't call an AsyncSocket's method directly from another thread, I have to use:
[self performSelectorOnMainThread:#selector(writeSomeData:) withObject:dataToWrite waitUntilDone:YES];
It does work, but I cannot get the response from my method "writeSomeData:" called this way, because performSelectorOnMainThread returns nothing.
The method writeSomeData: does something like this:
-(NSData *)writeData:(NSData *)dataToWrite {
dataReceived = nil; // AsyncSocket writes data to this variable
[asyncSocket writeData:dataToWrite withTimeout:-1 tag:0];
[asyncSocket readDataToData:[#"<EOF" dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0];
int counter = 0;
while (dataReceived == nil && counter < 5) {
// runLoop is [NSRunLoop currentRunloop]
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.3]];
++counter;
}
return [dataReceived copy];
}
I could get the response by accessing the class variable "dataReceived", but it's content is changed at this time.
Can anybody tell me how to use AsyncSocket (or generally, how to deal with run loop based classes) on separate threads, so that if I call a method of that class it blocks until the method is executed and a response is received?
Thank you.
Try using GCD(Grand Central Dispatch) to write your data on a separate thread and than come back to the main thread the moment that the data was written. You could do it like this:
// call this on the main thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSData *data = [self writeData:dataToWrite];
dispatch_async(dispatch_get_main_queue(), ^{
// do something with the data on the main thread.
});
});
I hope something like this can help you...

NSOperationQueue not reusing thread on iPhone

I'm using iPhone SDK 3.1.2, and the following code shows the NSOperationQueue does not reuse the thread for each task.
The code does not have any problems on Snow Leopard.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Override point for customization after app launch
[window addSubview:viewController.view];
[window makeKeyAndVisible];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue setMaxConcurrentOperationCount:1];
for(int i = 0; i < 100; i++) {
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(run) object:nil];
[queue addOperation:op];
[op release];
}
}
- (void)run {
static int tc = 0;
if([[NSThread currentThread] isMainThread]) {
NSLog(#"MAIN THREAD");
return;
} else if([[NSThread currentThread] name] == nil) {
[[NSThread currentThread] setName:[NSString stringWithFormat:#"THREAD_%d", tc++]];
}
NSLog(#"%#", [[NSThread currentThread] name]);
}
The output shows it create 100 threads to execute the 100 tasks.
2010-01-07 11:46:03.502 OperationQueueTest[7911:4503] THREAD_0
2010-01-07 11:46:03.506 OperationQueueTest[7911:4d03] THREAD_1
2010-01-07 11:46:03.507 OperationQueueTest[7911:4807] THREAD_2
2010-01-07 11:46:03.510 OperationQueueTest[7911:4d07] THREAD_3
2010-01-07 11:46:03.514 OperationQueueTest[7911:5007] THREAD_4
2010-01-07 11:46:03.516 OperationQueueTest[7911:4f0b] THREAD_5
2010-01-07 11:46:03.518 OperationQueueTest[7911:4e0f] THREAD_6
...
2010-01-07 11:46:03.740 OperationQueueTest[7911:4ea7] THREAD_97
2010-01-07 11:46:03.744 OperationQueueTest[7911:4dcf] THREAD_98
2010-01-07 11:46:03.746 OperationQueueTest[7911:460f] THREAD_99
NSOperationQueue is designed to pool and re-use threads in the most efficient way possible and in this instance, it seems it decided not re-using threads was the best way to go.
Test code has it's uses (and it is possible you may have identified a corner case where NSOperationQueue does not do the most efficient thing), but that doesn't mean that NSOperationQueue is always horribly inefficient when dealing with real code in real life; in fact my own experience has been to the contrary.
So I'd say use it in your real code and if you have performance issues, dig further into what it's doing with threads behind the scenes. Otherwise don't worry about it.
As an aside, if you are still curious, you might try recording the names of the threads into an array of NSStrings and then printing everything out at the end of the test code, rather than logging as you go along - this will significantly reduce the amount of work done by each NSInvocationOperation.
Snow Leopard's implementation of NSOperation/NSOperationQueue is now based on GCD.
The iPhone still uses the old Leopard implementation. So you can expect different results on each platform (Not to mention the completely different hardware).
It is possible that spawning new threads is the most efficient way to accomplish the tasks you are giving NSOperationQueue.
NSOperationQueue performs it's added operations asynchronously (in separate thread). So if we print thread information, then it is possible that we will get same thread object most of the time.
NSOperation object added in NSOperationQueue will different but thread objects can be same.
- (void)operaitonqueueTest
{
_opQueue = [[NSOperationQueue alloc] init];
[_opQueue setMaxConcurrentOperationCount:5];
for(int i = 0; i < 50; i++) {
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(run) object:nil];
[_opQueue addOperation:op];
}
}
- (void)run {
if([[NSThread currentThread] isMainThread]) {
NSLog(#"MAIN THREAD");
return;
}
NSLog(#"currentThread = %#", [NSThread currentThread]);
}