sem = dispatch_semaphore_create(0);
// called by NSOperationQueue
-(void)waitFromUI
{
NSLog(#"%#", [NSThread currentThread]); //<NSThread: 0x60000007d7c0>{number = 3, name = (null)}
NSLog(#"%ld",dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER));
}
// called by UI Button click
-(void)responseFromUI:(BOOL)response
{
NSLog(#"%#", [NSThread currentThread]); //<NSThread: 0x600000060840>{number = 1, name = main}
dispatch_semaphore_signal(sem);
}
Refer to the code, the workflow is first waitFromUI in NSOperation block, then show a UI by performSelectorOnMainThread in this block, then click the button in this UI to call responseFromUI.
the function dispatch_semaphore_wait is not ended after i call the dispatch_semaphore_signal, it waits forever and block my main thread.
Anybody knows what's the matter with my code.
Related
Is GKPlayer player is safe inside for loop?
for (GKPlayer *player in players) {
[player loadPhotoForSize:GKPhotoSizeSmall withCompletionHandler:^(UIImage *photo, NSError *error) {
if (!error && photo) {
if ([player.playerID isEqualToString:[GKLocalPlayer localPlayer].playerID]) {
currentUser.image = photo;
} else {
otherUser.image = photo;
}
}
}];
}
YES (assuming your code is only executed in main thread)
from Doc
When this method is called, it creates a new background task to handle the request. The method then returns control to your game. Later, when the task is complete, Game Kit calls your completion handler. The completion handler is always called on the main thread.
Your code is only executed in main thread so no thread-safety issue.
A possible execution sequence of your code is something like this
[player1 loadPhotoForSize...];
[player2 loadPhotoForSize...];
[player3 loadPhotoForSize...];
// method return
// photo for player3 downloaded
completionHandlerForPlayer3(photo, error);
// photo for player1 downloaded
completionHandlerForPlayer1(photo, error);
// photo for player1 downloaded
completionHandlerForPlayer2(photo, error);
Everything happened on main thread, it is not possible to have threading issue.
I have a series of dispatch_async that I am performing and I would like to only update the UI when they are all done. Problem is the method within dispatch_async calls something in a separate thread so it returns before the data is fully loaded and dispatch_group_notify is called before everything is loaded.
So I introduce a infinite loop to make it wait until a flag is set.
Is this the best way? See code below.
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_group_t group = dispatch_group_create();
for (...) {
dispatch_group_async(group, queue, ^{
__block BOOL dataLoaded = NO;
[thirdPartyCodeCallWithCompletion:^{
dataLoaded = YES;
}];
// prevent infinite loop
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)),
queue, ^{
dataLoaded = YES;
});
// infinite loop to wait until data is loaded
while (1) {
if (dataLoaded) break;
}
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
//update UI
});
}
You're already aware of dispatch groups. Why not just use dispatch_group_wait(), which includes support for a timeout? You can use dispatch_group_enter() and dispatch_group_leave() rather than dispatch_group_async() to make the group not done until the internal block for the third-party call with completion is finished.
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_group_t group = dispatch_group_create();
for (...) {
dispatch_group_enter(group);
dispatch_async(queue, ^{
[thirdPartyCodeCallWithCompletion:^{
dispatch_group_leave(group);
}];
}
}
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, NSECS_PER_SEC));
dispatch_async(dispatch_get_main_queue(), ^{
//update UI
});
The use of dispatch_group_wait() does make this code synchronous, which is bad if run on the main thread. Depending on what exactly is supposed to happen if it times out, you could use dispatch_group_notify() as you were and use dispatch_after() to just updates the UI rather than trying to pretend the block completed.
Update: I tweaked my code to make sure that "update UI" happens on the main queue, just in case this code isn't already on the main thread.
By the way, I only used dispatch_async() for the block which calls thirdPartyCodeCallWithCompletion: because your original used dispatch_group_async() and I wasn't sure that the hypothetical method was asynchronous. Most APIs which take a completion block are asynchronous, though. If that one is, then you can just invoke it directly.
Another method is to use semaphore and the dispatch_semaphore_wait:
// Create your semaphore, 0 is specifying the initial pool size
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
#autoreleasepool {
// Your code goes here
}
// Release the resource and signal the semaphore
dispatch_semaphore_signal(semaphore);
});
// Wait for the above block execution, AKA Waits for (decrements) a semaphore.
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// After this line you can now safely assert anything you want regarding the async operation since it is done.
I am trying to complete a long calculation with a determinate progress bar. This is working fine with the below code. However, in the method which calls scan, it immediately moves on to scoreWithEquation before scan has finished updating the StoredLibrary object. I've tried all the different methods for waiting for the dispatch queues to finish, but they all end up hanging the UI. Do I need to be using a callback? I've looked into this solution, but I don't understand how to pass all the arguments and return variables back and forth.
-(void) scan{
if (!_sheet){
[NSBundle loadNibNamed: #"ProgressSheet" owner: self];
}
[NSApp beginSheet: _sheet
modalForWindow: [[NSApp delegate]window]
modalDelegate: self
didEndSelector: NULL
contextInfo: nil];
[_sheet makeKeyAndOrderFront:self];
[_progressBar setIndeterminate:YES];
[_progressBar setMinValue:0];
[_progressBar startAnimation:self];
__block NSMutableArray *tempTracks = [[NSMutableArray alloc]init];
//do stuff
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//do stuff
[_progressBar setDoubleValue:0.f];
[_progressBar setMaxValue:[listTracks count]];
[_progressBar setIndeterminate:NO];
for (iTunesTrack *listTrack in listTracks) {
//do stuff to tempTracks
}
dispatch_async(dispatch_get_main_queue(), ^{
[_progressBar incrementBy:1];
});
}
}
dispatch_async(dispatch_get_main_queue(), ^{
[_progressBar setIndeterminate:YES];
[NSApp endSheet:self.sheet];
[self.sheet orderOut:self];
self.listTracks = tempTracks;
});
});
}
Below is the code which calls scan:
- (IBAction)evaluate:(id)sender {
if (self.storedLibrary == nil){
self.storedLibrary = [[StoredLibrary alloc] init];
[self.storedLibrary scan];
}
self.tableTracks = [self.storedLibrary scoreWithequation:[_scoringEquation stringValue]
sortOrder:[_sortOrder titleOfSelectedItem]
trackLimit:[_trackLimit integerValue]];
}
I would like to keep scan and scoreWithEquation as separate methods, as they are called elsewhere separately.
When you use dispatch_async the block dispatched will not block the current thread, and the execution will continue immediatly.
In your case, when you call scan, you do some stuff and then call dispatch_async to do other stuff. everything in the dispatch block will not be executed in this run loop and [self.storedLibrary scan] returns so scoreWithequation will be executed immediatly.
If you want to block the current thread (the thread on which the dispatch call is executed) you need to use dispatch_sync.
if you want to execute scoreWithequation after scan, you can create a serial_queue, and dispatch_async both scan and then scoreWithequation to the custom serial_queue. Doing so the execution will not block the current thread, and they will be executed in serie.
check "creating serial dispatch queue" ( http://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html )
or retaining a completion block to execute scoreWithequation as a callback is also a possibility.
I'm calling four methods that I want to execute in synchronous order, the first two methods are synchronous, the last two methods are asynchronous (data fetching from URLs).
Pseudo-code:
- (void)syncData {
// Show activity indicator
[object sync]; // Synchronous method
[object2 sync]; // Synchronous method
BOOL object3Synced = [object3 sync]; // Async method
BOOL object4Synced = [object4 sync]; // Async method
// Wait for object3 and object4 has finished and then hide activity indicator
}
How can I achieve this?
Use a barrier:
void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
Submits a barrier block for asynchronous execution and returns immediately.
When the barrier block reaches the front of a private concurrent
queue, it is not executed immediately.
Instead, the queue waits until its currently executing blocks finish executing.
At that point, the
queue executes the barrier block by itself. Any blocks submitted after
the barrier block are not executed until the barrier block completes.
This example outputs 1 2 3 4 done although being asynchronous, it could be 1 2 4 3 done. Since I understand you want to handle an activity indicator, this shouldn't matter.
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
#autoreleasepool {
dispatch_queue_t queue = dispatch_queue_create("com.myqueue", 0);
dispatch_sync(queue, ^(){NSLog(#"1");} );
dispatch_sync(queue, ^(){NSLog(#"2");});
dispatch_async(queue, ^(){NSLog(#"3");});
dispatch_async(queue, ^(){NSLog(#"4");});
dispatch_barrier_sync(queue, ^(){NSLog(#"done");});
}
}
For other ways to test asynchronous code, see: https://stackoverflow.com/a/11179523/412916
Assuming you actually have some sort of way of knowing when the asynchronous methods are done, what you probably want is something like:
- (void)syncData {
// Show activity indicator
[object sync]; // Synchronous method
[object2 sync]; // Synchronous method
_object3Synced = _object4Synced = NO;
[object3 syncWithCompletionHandler:
^{
_object3Synced = YES;
[self considerHidingActivityIndicator];
}]; // Async method
[object4 syncWithCompletionHandler:
^{
_object4Synced = YES;
[self considerHidingActivityIndicator];
}]; // Async method
}
- (void)considerHidingActivityIndicator
{
if(_object3Synced && _object4Synced)
{
// hide activity indicator, etc
}
}
You can make a subclass of UIActivityInidicator, add an activityCount property and implement these two additional methods:
- (void)incrementActivityCount
{
if(_activityCount == 0)
{
[self startAnimating];
}
_activityCount++;
}
- (void)decrementActivityCount
{
_activityCount--;
if(_activityCount <= 0)
{
_activityCount = 0;
[self stopAnimating];
}
}
Now whenever you start something that uses the activity counter call incrementActivityCount and in its completion block (or otherwise when it finishes) call decrementActivityCount. You can do other things if you want in these methods, the above is just a simple example which is probably sufficient in most cases (especially if you set hidesWhenStopped = YES).
You would need to launch the first Async method and use a completion block. In the completion block of the first async method, you would launch your second async method. Though this kind of makes using async methods irrelevant.
This is what my code looks like now and I want to call these methods in a serial manner:
-(void) methodOnBackThread // this method will run on a background thread
{
[runner runThisMethod]; // and this will run on the same background thread as well
[runner runThisOtherMethod]; // and so will this one
// but I want this one to run on the main thread :
[runner runThisMethodOnTheMainThreadUsing:thisParameter using:thisOtherParamater andUsing:thisOtherOneAsWell];
[runner runThisOtherMethod]; // this one will run on the background thread as well
// but I want this one to run on the main thread :
[runner runThisMethodOnTheMainThreadUsing:thisParameter using:thisOtherParamater andUsing:thisOtherOneAsWell];
[runner runThisOtherMethod]; // this one will run on the background thread as well
// etc..
}
I believe I have to use dispatch_get_main_queue but I can't figure out how to implement this in the above case.
How do I submit [runner runThisMethodOnTheMainThreadUsing:thisParameter using:thisOtherParamater andUsing:thisOtherOneAsWell]; to the Main Thread, then return to the execution of the rest of my background methods and then get the main thread again if the next method in line needs it?
If you are targeting iOS4 and aboveUse grand central dispatch. You can do something like this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//do some stuff here in the background
dispatch_async(dispatch_get_main_queue(), ^{
//do some stuff here in the main thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//do some stuff here in the background after finishing calling a method on the main thread
});
});
});
You can use dispatch_get_main_queue like:
dispatch_async(dispatch_get_main_queue(), ^{
if (backgroundTask != UIBackgroundTaskInvalid)
{
[runner runThisMethodOnTheMainThreadUsing:thisParameter using:thisOtherParamater andUsing:thisOtherOneAsWell];
}
});
For a better understanding about dispatch check this link