My code is like below, I am trying ot call a cpu intensive method inside an async block, but that method is not being always called, sometimes it's called, sometimes not.
-(IBAction) aMethod
//some code
dispatch_async(backgroundQueue, ^{
NSArray *allFiles = [appDel getAllFiles];
totalFilesCount = [allFiles count];
});
//some code
}
backgroundQueue is an instance variable declared in the interface file and created in the viewDidLoad method:
backgroundQueue = dispatch_queue_create("com.myapp.backgroundprocessing", NULL);
The method getAllFiles is sometimes called and sometimes not (checked with breakpoints), the reason I am calling it into a dispatch_async block is that it took a lot of time to return the result. What seems to be wrong with my approach, should it be called in the main thread although it's cpu intensive method?
backgroundQueue = dispatch_queue_create(..., NULL);
creates a serial queue, and not a concurrent queue as you assumed.
Therefore the block dispatched with
dispatch_async(backgroundQueue, ^{ ... });
is executed when all previous blocks dispatched to that queue have finished.
So if the first invocation is still running, it may look as if the second block
is not executed at all.
To create a concurrent queue, you would use
backgroundQueue = dispatch_queue_create(..., DISPATCH_QUEUE_CONCURRENT);
But you should check if it makes sense in your case to start another
(long running) [appDel getAllFiles] operation if the previous operation is still
running.
A possible alternative would be to start another [appDel getAllFiles] operation only
if the previous one has already finished, and to do nothing if the previous operation
is still running. That can be done e.g. with an NSOperationQueue:
if ([opQueue operationCount] == 0) {
[opQueue addOperationWithBlock:^{
NSArray *allFiles = [appDel getAllFiles];
totalFilesCount = [allFiles count];
}];
}
Related
I have a thread call in objective C and i want once this thread ends i want to return a value ;the value will be changed inside the thread
So the method must not return the value unless the tread ends
Here is the code i use:
[NSThread detachNewThreadSelector:#selector(CheckBeforePrint2) toTarget:self withObject:nil];
This is My Full Code
- (NSString *) getStatusPrinter:(NSString *) printerSerialNumber
{
self.printerSN = printerSerialNumber;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *Result = #"-1";
[NSThread sleepForTimeInterval:2.0f];
[NSThread detachNewThreadSelector:#selector(CheckBeforePrint) toTarget:self withObject:Result];
[pool release];
return Result;
}
Now i want to wait for the value of Result and return it i am using
cocoa
And i am returning the value to another app
Can anyone help in that.
Thanks
What you are doing here requires the use of a semaphore for example. If there is nothing more to it than you are providing here then a completion block to a background running method is the best way to do it. See option 2 below
Either way, why do you want the parent thread (the thread dispatching a new thread) to wait for another thread? If the parent thread is waiting, it is locked until the dispatched thread is done (according to your requirement). This situation is redundant because the whole point of dispatching another thread is so that the parent thread can continue with other things. Unless of course the parent thread needs to wait for multiple threads, then it makes sense to lock it.
Having said that, its best to just let the dispatching thread / parent thread do the processing that you are dispatching on to another thread. Im only saying this given the details you have provided.
OPTION 1 use a semaphore
Use a semaphore to lock and unlock parent thread
-(void)getStatusPrinter()
{
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[NSThread detachNewThreadSelector:#selector(checkBeforePrint2) toTarget:self withObject: semaphore];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
[self print]; // this will run after semaphore is unlocked
}
-(void)checkBeforePrint2:(dispatch_semaphore_t)sem
{
//this is within child thread
//do some processing,
dispatch_semaphore_signal(sem);//unlock semaphore
}
But, as I mentioned before, this situation seems redundant because the parent thread waits (therefore unusable) for child thread; why can't it just do the work itself...
OPTION 2 use completion block (PREFERABLE)
Use a completion block that you pass to the child thread. This allows the parent thread to continue. If it is the main thread it remains free for UI stuff.
-(void)getStatusPrinter()
{
[self checkBeforePrint2WithCompletion: ^{
[self print];
}];
//continue with more stuff
}
-(void)checkBeforePrint2WithCompletion:(void (^ __nullable)(void))completion
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//do something before executing completion code
if(completion){
completion();
}
});
}
Disclaimer: there may be typos in this code as it was not written in an editor/ IDE. Please comment if any.
UPDATE in response to added details.
Okay, for the fact that you said you need to return the result to another application, that means the entry thread at getStatusPrinter can not be allowed to return after dispatching a new thread. If you really need to create a new thread for CheckBeforePrint then the entry thread has to wait. That to me is pointless. You can simply run everything on the entry thread.
If you are using openURL:options:completionHandler: then the entry thread doesn't need to wait. The value of result can be passed back within the completion block.
Please refer to Apple's documentation on openURL with a completion handle
I have a use case where i am writing data to local couchebase database in ios. Here it will not support concurrent access of write operation. So i want to run the CRUD operation on main thread and return result after running some algorithm on data on secondary threads. when main thread took over control and executes code, current running thread is not waiting till main thread completes its operation. How can i handover result from main thread to other thread.
Ex :
+(BOOL)createDocument:(NSDictionary*)data withId:(NSString*)docId {
__block CBLDocument* doc = nil;
// NSLog(#"%d count ", [[self database] documentCount]);
dispatch_async(dispatch_get_main_queue(), ^{
if(docId.length > 0) {
doc = [[self getDatabase] documentWithID:docId];
} else {
doc = [[self getDatabase] createDocument];
}
});
//I want current thread to wait till main thread completes its execution
if(doc){
return YES;
}else{
return NO;
}
}
If you know for a fact that this method is not called from the main queue, you can use dispatch_sync:
+(BOOL)createDocument:(NSDictionary*)data withId:(NSString*)docId {
__block CBLDocument* doc = nil;
dispatch_sync(dispatch_get_main_queue(), ^{
if(docId.length > 0) {
doc = [[self getDatabase] documentWithID:docId];
} else {
doc = [[self getDatabase] createDocument];
}
});
//I want current thread to wait till main thread completes its execution
if(doc){
return YES;
}else{
return NO;
}
}
A more generalized approach would be to create a dedicated, custom dispatch queue for your database interaction. Then, any thread (either the main thread or any background thread) that wants to interact with the database would perform a dispatch_sync to that dedicated queue.
This provides a cleaner implementation, making the functional intent more explicit, and ensures that database interaction initiated from a background thread will not block the main thread (unless, of course, the main thread happens to be initiating database interactions with this database queue at the same time). This dedicated queue approach is in the spirit of the "One Queue per Subsystem" design pattern discussed in WWDC 2012 video, Asynchronous Design Patterns with Blocks, GCD, and XPC (it's the fifth design pattern discussed in the latter part of the video).
You can make another dispatch_async call to your "current thread" from the main thread. So you'll use another function block and put your if(doc) stuff into that. That's how chaining between threads are handled with GCD API.
So the problem with your code is, createDocument returning after dispatching to another thread. Instead, you should change createDocument to take a function block argument.
+(BOOL)createDocument:(NSDictionary*)data
withId:(NSString*)docId
onComplete:(void (^)(CBLDocument*))onComplete;
And change your dispatch_async call as follows:
dispatch_async(dispatch_get_main_queue(), ^{
if(docId.length > 0) {
doc = [[self getDatabase] documentWithID:docId];
} else {
doc = [[self getDatabase] createDocument];
}
dispatch_async(yourCurrentThread, ^{
onComplete(doc);
});
});
However if you really want to BLOCK your current thread, you should use dispatch_sync instead of dispatch_async.
dispatch_sync(dispatch_get_main_queue(), ^{
...
});
return doc != nil;
Sorry if there are any syntax errors, I haven't tested this.
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.
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:
Queues are not bound to any specific thread of execution and blocks submitted to independent queues may execute concurrently.
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:
All memory writes performed by a block dispatched to a serial queue are guaranteed to be visible to subsequent blocks dispatched to the same queue.
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:
Prerequisites:
A NSMutableArray (let's call it blockQueue).
A NSCondition (let's call it queueCondition).
Create a new NSThread.
The thread's method has an endless loop in which it locks the condition, waits for it if the queue is empty (and the "quit" bool is false), dequeues a block and executes it.
A method that locks the condition an enqueues the block.
Due to the condition, the thread will simply sleep while there's no work to do.
So, roughly (untested, assuming ARC):
- (void)startWorkerThread
{
workerThread = [[NSThread alloc]
initWithTarget:self
selector:#selector(threadMain)
object:nil
];
[workerThread start];
}
- (void)threadMain
{
void (^block)();
NSThread *currentThread;
currentThread = [NSThread currentThread];
while (1) {
[queueCondition lock];
{
while ([blockQueue count] == 0 && ![currentThread isCancelled]) {
[queueCondition wait];
}
if ([currentThread isCancelled]) {
[queueCondition unlock];
return;
}
block = [blockQueue objectAtIndex:0];
[blockQueue removeObjectAtIndex:0];
}
[queueCondition unlock];
// Execute block outside the condition, since it's also a lock!
// We want to give other threads the possibility to enqueue
// a new block while we're executing a block.
block();
}
}
- (void)enqueue:(void(^)())block
{
[queueCondition lock];
{
// Copy the block! IIRC you'll get strange things or
// even crashes if you don't.
[blockQueue addObject:[block copy]];
[queueCondition signal];
}
[queueCondition unlock];
}
- (void)stopThread
{
[queueCondition lock];
{
[workerThread cancel];
[queueCondition signal];
}
[queueCondition unlock];
}
Untested Swift 5 port:
var workerThread: Thread?
var blockQueue = [() -> Void]()
let queueCondition = NSCondition()
func startWorkerThread() {
workerThread = Thread() {
let currentThread = Thread.current
while true {
self.queueCondition.lock()
while self.blockQueue.isEmpty && !currentThread.isCancelled {
self.queueCondition.wait()
}
if currentThread.isCancelled {
self.queueCondition.unlock()
return
}
let block = self.blockQueue.remove(at: 0)
self.queueCondition.unlock()
// Execute block outside the condition, since it's also a lock!
// We want to give other threads the possibility to enqueue
// a new block while we're executing a block.
block()
}
}
workerThread?.start()
}
func enqueue(_ block: #escaping () -> Void) {
queueCondition.lock()
blockQueue.append(block)
queueCondition.signal()
queueCondition.unlock()
}
func stopThread() {
queueCondition.lock()
workerThread?.cancel()
queueCondition.signal()
queueCondition.unlock()
}
In GCD: no, that's not possible with the current lib dispatch.
Blocks can be executed by dispatch lib on whatever thread which is available, no matter to which queue they have been dispatched.
One exception is the main queue, which always executes its blocks on the main thread.
Please file a feature request to Apple, since it seems justified and sound. But I fear it's not feasible, otherwise it would already exist ;)
You can use NSOperationQueue. You can make it use just one thread by using method - (void)setMaxConcurrentOperationCount:(NSInteger)count. Set it to 1
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.
If you want to perform a selector in Main Thread, you can use
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait
and if you want to it to perform in background thread
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)object
and if you want to perform in any other thread use GCD(Grand Central Dispatch)
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//code to be executed on the main queue after delay
});
You can either use NSOperationQueue with a MaxConcurrentOperationCount of 1 or go the manual way down the road by using NSThread 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.
Never tried this but this might do the trick. Use separate properties of atomic dispatch queues for each operation.
#property (strong, atomic) dispatch_queue_t downloadQueue;
Queue/Thread 1 for first operation
downloadQueue = dispatch_queue_create("operation1", NULL);
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.
Just like this,
dispatch_asyn(dispatch_get_current_queue, ^ {
});
In my iOS application, I have a database call that takes some time to complete. I have a spinner visible on the screen while this operation is taking place. I am hitting an error with the app crashing with "com.myapp failed to resume in time" so it seems like it is running the database call on the main thread, causing issues.
Current Code
-(void)timeToDoWork
{
...
[CATransaction flush];
[[DatabaseWorker staticInstance] doWork];
//Additional UI stuff here
...
if([self->myReceiver respondsToSelector:self->myMessage])
{
[self->myReceiver performSelector:self->myMessage];
}
}
To get the doWork function to take place on a background thread, it looks like I can use Grand Central Dispatch:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
[[DatabaseWorker staticInstance] doWork];
});
However, how do I prevent the execution from continuing until it is complete? Should I end the method after the doWork call, and move everything below it to a new function?
Sample
-(void)timeToDoWork
{
...
[CATransaction flush];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
[[DatabaseWorker staticInstance] doWork];
dispatch_async(dispatch_get_main_queue(), ^{
[self doneDoingWork];
});
});
}
-(void)doneDoingWork
{
//Additional UI stuff here
...
if([self->myReceiver respondsToSelector:self->myMessage])
{
[self->myReceiver performSelector:self->myMessage];
}
}
Is there a better way to do this?
Prevent execution in main thread from continuing is really bad idea. iOS will terminate your application since main thread should always work with run loop.
I suggest you following way to handle your problem:
Write a "Locker". Let it show some view with animated spinner and no buttons at all.
When you start dispatch async operation just bring it to the front and let it work with run loop.
When your async operation completes close the locker.
You can also use blocks.
e.g..
- (void)doWorkWithCompletionHandler:(void(^)())handler {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// do your db stuff here...
dispatch_async(dispatch_get_main_queue(), ^{
handler();
});
});
}
And then use it like that:
[[DatabaseWorker staticInstance] doWorkWithCompletionHandler:^{
// update your UI here, after the db operation is completed.
}];
P.S.
It might be a good idea to copy the handler block.
The error you are receiving suggests that you are doing something in application:didFinishLaunchingWithOptions: or applicationDidBecomeAction: or somewhere else in the launch cycle that is taking too long and the app is getting terminated by the launch watchdog timer. Above all, it is vital that you return as quickly as possible from these methods. I'm not sure where your code fits into the launch cycle; but this explanation seems plausible.
There are all sorts of ways to address this; but taking the lengthy process off the main queue is the first step as you noted. Without knowing more about what main queue objects (e.g. UI) depend on this database transaction, I'd say that your suggested solution is perfectly fine. That is, dispatch the work to a background queue; and on completion dispatch the remaining UI work to the main queue.
Delegates were suggested elsewhere as a solution. That's also workable although you still have to concern yourself with which queue the delegate methods get called on.
I think that you should use a delegate in your DatabaseWorker and the method doWork always run in background, so when the worker finish the work it tell to its delegate that the work is finished. The delegate method must be called in the main thread.
In the case that you have many objects that need to know when the DatabaseWorker finish instead to use a delegate I would use notifications.
EDIT:
In the DatabaseWorker class you need to implement the method doWork like this:
- (void) doWork{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
//Do the work.
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate finishWork];
});
});
}
And in the class that implement timeTodoWork:
-(void)timeToDoWork
{
...
[CATransaction flush];
[[DatabaseWorker staticInstance] setDelegate:self];
[[DatabaseWorker staticInstance] doWork];
}
#pragma mark DatabaseWorkerDelegate
- (void) finishWork{
//Additional UI stuff here
...
if([self->myReceiver respondsToSelector:self->myMessage])
{
[self->myReceiver performSelector:self->myMessage];
}
}
Also you can use:
[self performSelectorInBackground:#selector(doWorkInBackground) withObject:nil];
instead of:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
//Do the work.
});
And add a method:
- (void) doWorkInBackground{
//Do the work
[self.delegate performSelectorOnMainThread:#selector(finishWork) withObject:nil waitUntilDone:NO];
}
Here is what I need to do.
I hope dispatch_sync would be the best way to do it using GCD
I have a certain piece of critical section code that is placed in the applicationDidBecomeActive callback in Appdelegate..
I am wrapping up that method inside a dispatch_sync call so that it gets called only once no matter how many times applicationDidBecomeActive is called
- (void)applicationDidBecomeActive:(UIApplication *)application{
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(#"Thread created");
//crtical code
[self runCriticalSection];
});}
Is this the right way for doing it using dispatch_sync?
dispatch_sync() does not return until the block has finished, which means that
applicationDidBecomeActive does not return until runCriticalSection has finished
execution.
This is probably not what you want, therefore you have to use dispatch_async() (as already
stated in the other answer).
But you don't want another runCriticalSection to start
if the previous one is still running. This can be achieved with a "counting semaphore"
(which are also a feature of GCD):
static dispatch_semaphore_t sema; // The semaphore
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// Initialize with count=1 (this is executed only once):
sema = dispatch_semaphore_create(1);
});
// Try to decrement the semaphore. This succeeds if the count is still 1
// (meaning that runCriticalSection is not executing), and fails if the
// current count is 0 (meaning that runCriticalSection is executing):
if (dispatch_semaphore_wait(sema, DISPATCH_TIME_NOW) == 0) {
// Success, semaphore count is now 0.
// Start asynchronous operation.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//critical code
[self runCriticalSection];
// Increment the semaphore count (from 0 to 1), so that the next call
// to applicationDidBecomeActive will start a new operation:
dispatch_semaphore_signal(sema);
});
}
The runCriticalSection method will be called multiple times, just not concurrently, so I don't know if this is what you want to achieve.
dispatch_sync just add the specified block to a serial queue (the default priority global queue), so if applicationDidBecomeActive gets fired two times in a row, the queue will contain two blocks that will run runCriticalSection. As the first one starts and finishes its execution, the second one will start, so there will not be any execution of the two blocks at the same time.
Is this the expected behavior? If so, dispatch_sync is the way to go.
As an add-on: if runCriticalSection performs an heavy operation, consider that dispatch_sync will block the thread that runs the applicationDidBecomeActive method (the main one if you don't call the method by hand from another thread) until that operation is finished.
If you want to avoid this, you should do something like:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self runCriticalSectionOnComplete:^{
// If you want to perform something on completion, place it here. This is called asynchronously, without blocking the main thread.
}];
});
dispatch_async will return as soon as the block is added to the queue, while dispatch_sync waits for the code inside the block to be completed.