This question already has an answer here:
Async request does not enter completion block
(1 answer)
Closed 3 years ago.
i am new to Objective C, i have one question regarding dispatch. Does anyone know why the block added to the queue is not run?
int main(int argc, const char * argv[]) {
#autoreleasepool {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"hello world");
});
};
return 0;
}
Your program is exiting before the asynchronously dispatched block had a chance to execute. This code is basically saying “dispatch this log statement to run when the main thread for this program is free”, but is also effectively saying “dispatch that block of code run asynchronously (i.e. later) but then immediately exit”. As you can imagine, it’s just exiting before it gets around to being able to execute that dispatched block.
This pattern of dispatching code to run asynchronously makes most sense when you’re writing a full-fledged “app” (with UI where the user can do stuff and quit the app at a time of their choosing), rather than a “command line tool”. If you do this in an app, you will see your NSLog statement. So, when creating your test project, create an “app” rather than a “command line tool”. Then you’ll see your log statement fine.
This notion of dispatching code to run asynchronously (esp when you dispatch that to the main queue) doesn’t quite make sense for most command line tools. Theoretically you could create your own “run loop” to keep the command line tool alive until your dispatched block has a chance to run, but that’s not a very common pattern. Most command line tools just do something and then exit, and don’t have asynchronous blocks running.
If there’s some reason you feel like you really want to do this in a command line app, please edit your question to describe your scenario in greater detail. If you are just experimenting with GCD, it’s just simpler to do this with an “app” rather than a “command line tool”.
Related
I'm getting to know the NS/Objective-C model of concurrency. Say I have a command line tool that does something like this:
#include "myLibrary.h"
void callback(void* parameter){
cout<<"callback called.\n";
//some logic...
}
int main(int argc, char* argv[]){
myLibraryInit(callback);
std::string s;
while(true){
cin>>s;
myLibrarysResponseTo(s);
}
}
In my library, I'd like to be able to have two responses. One which starts a repeating timer and one which stops it. The timer should call the callback supplied to the library by myLibraryInit.
I've used NSTimers before in iPhone/iPad apps, and I think the problem stems from the different paradigm command line tools have. The main thread goes into main and never finishes it until the program is finished. This means it's not free to run the main run loop, which is what gets the timer going. I think. So how do I make an NSTimer work in this context?
The other thing is that Apple NSTimer documentation says I need to invalidate an NSTimer on the same thread it was installed. I don't know how to figure out what thread I was on when I installed the timer, and then keep track of it (and ensure it stays alive) until I want to invalidate the timer. I'm not sure if I'm just missing an obvious mapping between threads and dispatch queues, run loops, or something else. I am using core bluetooth and I initialize a central manager like so:
_centralManager=[[CBCentralManager alloc]
initWithDelegate: self
queue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
];
so a callback may be triggered from here. If the callback includes some logic to call the library function that stops the timer, I can't guarantee from which thread came the invalidate. So how do I properly invalidate the timer?
I found this question but it doesn't allow a main to happen at the same time as the run loop that that the timer is on.
I hope I gave enough context. Thanks in advance for your replies.
You must call dispatch_main() or run an NSRunLoop in the main thread if any of the system frameworks [that use GCD or asynchronous operations] are to work correctly.
This can be as simple as calling [[NSRunLoop currentRunLoop] run]; at the end of your main() function (just make sure you schedule the kickoff work first as that method never returns).
Is it possible to use the AppName-Prefix.pch file to import a given header file in all source files except one?
Problem:
I have followed the approach described here: https://stackoverflow.com/a/617559/1062572 to overwrite a C function call, namely the GCD dispatch_async function.
Now I need to import the header file intercept.h in all my source files and for that I tried to use the AppName-Prefix.pch file. However this also imports the header file in my implementation file intercept.m. This cause an endless call loop because I try to call the original dispatch_async in there.
Heres my header file intercept.h:
#ifdef INTERCEPT
#define dispatch_async(queue, block) my_dispatch_async(queue, block)
#endif
And heres is my implementation file intercept.m:
void my_dispatch_async(dispatch_queue_t queue, dispatch_block_t block) {
NSLog(#"\nBlock is enqueued!\n");
dispatch_async(queue, ^{
NSLog(#"\nBlock is dequeued!\n");
block();
NSLog(#"\nBlock has executed!\n");
});
}
Here is my Prefix.pch file:
#ifdef INTERCEPT
#import "Intercept.h"
#endif
How can I import the header file in all my sources, with the implementation file as the only exception? I hope it can be done without manually having to insert an import statement in every source file. And without writing a script to do it. ;)
One thing that confuses me even more is: Actually I have the implementation file in a compiled library (Testing.a), so why is the header file imported in it?
Even more information:
I am writing a test framework that waits until all async tasks has completed before checking the results. That why I override dispatch_async. Any other suggestion is welcome. :)
Also I have noticed this answer: https://stackoverflow.com/a/617606/1062572 However it seems that this will not work on OSX, hence not iOS which is my target.
All these approaches will only overwrite the function call in my own source code. Actually I want it to overwrite it everywhere. However for this question I am satisfied if it works for my own source code.
Unfortunately, its not possible. Prefix headers are compiled, cached and included in every file during compilation. You can't tell which files to ignore.
However you can ignore it if you already included the Intercept.h. Here's how:
1- Remove ifdef INTERCEPT condition around #import "Intercept.h" from Prefix.pch. You don't need it there.
2- Update your Intercept.h to:
#ifndef INTERCEPT_H
#define INTERCEPT_H
#define dispatch_async(queue, block) my_dispatch_async(queue, block)
#endif
What happens here is that you first checked whether INTERCEPT_H is already included/defined in current definition, if not, you defined it in the next line and then defined your macro.
Now, the #ifndef INTERCEPT_H condition will return false if it has already included its content in the same context.
Hope it helps.
Even more information: I am writing a test framework that waits until all async tasks has completed before checking the results. That why I override dispatch_async. Any other suggestion is welcome. :)
Depending on your situation, this is likely solvable in better ways. As long as you have access to which queues are being used, it's pretty simple. Consider this API, where you are passing the queue to be used:
[object doSomethingAsyncWithCompletion:block1 queue:myQueue];
[object doSomethingElseAsyncWithCompletion:block2 queue:myQueue];
[object doMoreAsyncWithCompletion:block3 queue:myQueue];
Now, you want to wait until all those finish. Assuming this is a custom concurrent queue (not one of the global queues), just use a barrier:
dispatch_barrier_sync(myQueue, ^{
NSLog(#"This will not run until everything else before it on the queue finishes.");
}
But what if you don't know what queue is being used? Well, as long as you control the completion blocks, that's fine, too. (See Waiting on Groups of Queued Tasks.)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_block_t doneBlock = ^{
dispatch_group_leave(group);
}
dispatch_group_enter(group);
[object doSomethingAsyncWithCompletion:doneBlock queue:myQueue];
dispatch_group_enter(group);
[object doSomethingElseAsyncWithCompletion:doneBlock queue:myQueue];
dispatch_group_enter(group);
[object doMoreAsyncWithCompletion:doneBlock queue:myQueue];
// Wait for all the doneBlocks to fire
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);
Of course you could also do this with a semaphore. That's sometimes easier if you just want to convert a single operation from asynchronous to synchronous.
I'd recommend these kinds of approaches rather than trying to hijack dispatch_async itself.
I'm programming an application that makes use of asynchronous web requests using NSURLConnection, so I have multiple threads running. To ensure that the main logic of my app happens on one thread, I am making heavy use of performSelectorOnMainThread:waitUntilDone:. Sometimes though, I am running this on the main thread, which piqued my curiosity.
If performSelectorOnMainThread:waitUntilDone: is called while in the main thread? Does it act the same as just performSelector:? What if waitUntilDone: is YES? What if it is NO?
EDIT: I have found that when waitUntilDone: is YES, the selector is executed (almost) immediately, but I cannot figure out when it is executed if waitUntilDone: is NO.
performSelectorOnMainThread:withObject:waitUntilDone:
is a method to deliver message on main thread of your application. Here boolean value in parameter waitUntilDone: specifies that whether you want to block your main thread to execute specified selector or not.
for example -
if you written these two lines-
[self performSelectorOnMainThread:#selector(print) withObject:nil waitUntilDone:YES];
NSLog(#"Hello iPhone");
and this is the print method -
- (void) print
{
NSLog(#"Hello World");
}
then you will get this o/p
Hello World
Hello iPhone
so it first pause the execution of your main thread and print "Hello World" and then execute main thread again and print "Hello iPhone" because you specified YES in waitUntilDone:
but if you specified NO in waitUntilDone: then it will print like this -
Hello iPhone
Hello World
it clearly indicates that it put your request of executing the specified selector in a queue and as OS gets its main thread free it executed you request.
Calling performSelectorOnMainThread:withObject:waitUntilDone: either from main thread or a secondary thread doesn't make any difference in it's execution, it depends on what you specified in waitUntilDone:
for more info -
NSObject Class Reference
If the current thread is also the main thread, and you pass YES,
the message is performed immediately, otherwise the perform is
queued to run the next time through the run loop.
If YES, it can be performed before performSelectorOnMainThread:withObject:waitUntilDone: returns.
I have found that when waitUntilDone: is YES, the selector is executed (almost) immediately, but I cannot figure out when it is executed if waitUntilDone: is NO.
The bit about the run loop: Your main thread has a run loop. This more or less prevents a thread from exiting. A run loop manages a todo list. When its work is complete, it suspends execution of that thread for some time. Then it wakes up later and sees if has work to do.
The amount of work can vary greatly (e.g. it may do some really heavy drawing or file i/o between the time it awakes and the point your selector is performed. Therefore, it's not a good tool for really precise timing, but it should be enough to know how it works and how the implementations adds the work to the run loop.
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html
If waitUntilDone: is YES it acts as an immediate function call.
If waitUntilDone: is NO then it queues the call along with all other threads' calls.
This method queues the message on the run loop of the main thread
using the common run loop modes—that is, the modes associated with the
NSRunLoopCommonModes constant. As part of its normal run loop
processing, the main thread dequeues the message (assuming it is
running in one of the common run loop modes) and invokes the desired
method.
As noted above, things like drawing and I/O are prioritized over anything in queues. Once the main thread gets around to having time for queue service in the next event loop, there's a couple other details that make it not quite as simple as counting on first in first out:
1) dispatch_async() blocks ignore modes.
2) The performSelector variants with a specific mode argument -- event tracking, say -- may take precedence over ones with the default common modes argument in a loop running in that specific mode.
As a general rule, if you want predictable timing behaviours you should use the low level GCD dispatch functions that don't take account of higher level considerations like run loop modes.
void _WebThreadLockFromAnyThread(bool), 0x205acdf0: Obtaining the web lock from a thread other than the main thread or the web thread. UIKit should not be called from a secondary thread.
This look serious. I want the program to break at that point. I do not feel I access UIKit anywhere from outside the main thread.
However, the warning is just there and I don't know where in my code that happens
This means your code is called from non-main thread at some point. The problem is you don't remember or don't know where. You just feel you didn't but actually your code does.
My recommendation is heavy dynamic assertion. Install thread-check assertion on every suspicious methods and functions. For example,
- (void)test
{
NSAssert([[NSThread currentThread] isMainThread], #"This code is expected to be called from main thread!");
}
And then the assertion will eventually make your app to crash on invalid thread context. If you're not that lucky, you may install the assertion on every method literally.
Anyway once you got the assertion failure, you can start at there. And if you found the bad point, following steps are just trivial.
FACTS:
I have a method executing on a background thread :
[currentGame performSelectorInBackground:#selector(playOn:) withObject:self];
This method basically contains a while loop that keeps on executing until the user clicks on a Quit button:
-(void) playOn: (UIViewController*) thisViewController
{
while(!quitButtonPressed)
{
// this is my method's main loop
}
}
PROBLEM:
If the user clicks on Quit somewhere in the middle of the above loop
the rest of the loop would have to execute before it checks the BOOL once again and eventually stops. In order to prevent that from
happening and have the while-loop stop as soon as the user clicks on
Quit, I guess I could also add many if(quitButtonPressed) break;
here and there in my while loop in order to semi-constantly check and "immediately" break away if needed. However, this doesn't seem
very clever or practical from a design perspective given the size of
the above main while-loop and the fact that it contains many smaller
while-loops inside of it (the number of if.. break; I would have to
add would be quite big and could make things quite complicated to
figure out..)
POSSIBLE SOLUTION (but is it the right one?) :
So I was thinking that the best way would be to stop/cancel the
background thread on which the above method's while loop is executing,
instead of the while-loop itself, inside the method, the moment the
user clicks on Quit
Is this, or something similar (i.e. a better suggestion), possible and
how exactly could I do this?
POSSIBLE IMPLEMENTATION OF ABOVE SOLUTION:
I could create this new method:
-(void)checkQuitButton
{
while(!quitButtonPressed)
{
//wait
}
if(quitButtonPressed)
{
// stop this thread-->[currentGame performSelectorInBackground:#selector(playOn:) withObject:self];
// this is the method I'm looking for
}
}
And then I could start executing the above and my previous main method concurrently on two separate background threads as follows:
[currentGame performSelectorInBackground:#selector(playOn:) withObject:self];
[currentGame performSelectorInBackground:#selector(checkQuitButton) withObject:nil];
While the game while-loop is being executed another while-loop is checking the QuitButton at the same time. But is there a method that I can actually call in order to cancel what was started here:
[currentGame performSelectorInBackground:#selector(playOn:) withObject:self];
?
The correct solution is to periodically check for a "stop" flag. Abruptly terminating a thread provides no opportunity to clean up resources. In short, you would leak memory terribly.
But the deeper issue is that you almost certainly should not have this kind of thread. It strongly suggests an incorrect design. In iOS, most background operations should take the form of focused operations, implemented either with NSOperation or blocks with Grand Central Dispatch. You should very, very seldom need a long lived thread that is performing many different kinds of functions. Within your operation, it should be fairly straightforward where to put the "check for cancel" statements.
There is also almost no case where you should use performSelectorInBackground:. It is an incredibly dangerous method that gives you very little control. Instead, read the Concurrency Programming Guide for guidance on how to properly implement background operations. Pay special attention to the section "Migrating Away From Threads."