Make main thread wait until all other threads done in IPhone sdk - ios

I am working on threads in objective C for the first time in my coding experience. In my app i needs to download some assets in two threads. After completion of downloading i have to start my main thread which will make use of the downloaded assets in threads. So i wrote some code like this
NSThread *threadPlayer1 = [[NSThread alloc]initWithTarget:self selector:#selector(getPlayer1Assets) object:nil];
           
[threadPlayer1 start];
           
NSThread *threadPlayer2 = [[NSThread alloc]initWithTarget:self selector:#selector(getPlayer2Assets) object:nil];
           
[threadPlayer2 start];
[self performSelectorOnMainThread:#selector(introducePlayer1) withObject:nil waitUntilDone:YES];
I wrote waituntilDone to Yes but it waits until the first thread completes only.
so if i wants to wait untill all the two threads completed what should i do? can any one suggest with sample code snippets.

What I would suggest, would be to use this. It's from Pulse Engeenering Blog. Spend a bit of time in it, until you grasp the idea.
As for your code. I guess you are doing this:
[self performSelectorOnMainThread:#selector(introducePlayer1) withObject:nil waitUntilDone:YES];
On the main thread. Read what is said about it on the documentation, specially the last sentence:
wait A Boolean that specifies whether the current thread blocks until
after the specified selector is performed on the receiver on the main
thread. Specify YES to block this thread; otherwise, specify NO to
have this method return immediately.
If the current thread is also the main thread, and you specify YES for
this parameter, the message is delivered and processed immediately.

Related

android google play integrity exponential backoff retry is blocking main application thread

// Create an instance of a manager.
IntegrityManager integrityManager =
    IntegrityManagerFactory.create(getApplicationContext());
// Request the integrity token by providing a nonce.
Task<IntegrityTokenResponse> integrityTokenResponse =
    integrityManager
        .requestIntegrityToken(
            IntegrityTokenRequest.builder().setNonce(nonce).build());
integrityTokenResponse.addOnSuccessListener(this::handleSuccess);
integrityTokenResponse.addOnFailureListener(this::handleFailure);
in handleFailure listener I have retry logic with Thread.sleep(retryMillis) which is running on main thread and blocking the UI requests.
Can someone help me how to do retry without blocking main thread or how to run play integrity in a different thread.?
After reading a bit more from this link, I realized that addOnFailureListener(this::handleFailure); constructor with a listener function always runs on main thread. I'm able to solve the problem by changing failurelistener as mentioned below by adding threadpool executor :
integrityTokenResponse.addOnFailureListener(executor, this::handleFailure);

How can I "visualize"(observe) a thread exiting in iOS?

When learning thread and run loop, I notice that some articles say: "Generally, a thread just exits once it has done its work." So there is necessity sometimes to create a so-called "immortal thread"(?? I don't know the exact term in English) using NSRunloop.
The question is HOW can I prove the statement "just exits once it has done its work"? I code like this
- (void)doSomethingOnThread {
// dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// NSLog(#"I'm on thread %#", [NSThread currentThread]);
// });
NSThread *thread1 = [[NSThread alloc] initWithBlock:^{
NSLog(#"I'm on thread %#", [NSThread currentThread]);
}];
thread1.name = #"thread1";
[thread1 start];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(threadExitHandler:) name:NSThreadWillExitNotification object:nil];
}
- (void)threadExitHandler:(NSNotification *)noti {
NSLog(#"Thread will exit: %#", noti);
}
Well, the notification handler is not called.
So, [1]: How can I prove a thread exiting? [2]: What kinds of threads behave so?(I know the main thread will never exit, what about other thread? GCD threads, for example?)
If you want to visualize it, I might use the debugger. For example, I've set a breakpoint inside a NSThread subclass and I see the thread listed in the left panel in Xcode:
But if I have another breakpoint triggered one second after the main method finishes, I see the relevant “Thread will exit” message and my thread is no longer present :
Or you could add a NSLog statement inside the dealloc method for your NSThread subclass, and that also would demonstrate its deallocation. Or look for the subclass in the debug memory object graph.
Well, the notification handler is not called.
I'd suggest you add your observer for NSThreadWillExitNotification before you start your thread. Right now you have a race condition between the starting and exiting of this thread and the adding of the observer. FWIW, I do see the “Thread will exit” message.
Unrelated, while it’s great to learn about threads and runloops, it has little practical use nowadays. It might be more useful to master GCD which gets us out of the weeds of threads and offers performance optimizations and a richer API for writing robust multi-threaded code.
In regards to whether GCD creates persistent threads or not, the answer is yes, but we're abstracted away from this detail. But one of GCD’s performance optimizations is that it manages a “pool” of threads for us, not constantly spinning up new threads and destroying them constantly for every dispatched block of code.
You might want to watch WWDC 2016’s Concurrent Programming With GCD in Swift 3. It walks through the relationship between queues, threads, and runloops.

DispatchQueue bound to exact Thread

im developing an app, which uses some framework to draw 3D staff via openGL. This framework requires me to call draw() method from exact the same Thread.
So i created a serial DispatchQueue and started CADisplayLink in it, calling draw() at 60FPS. There are few other methods that i have to call from this exact thread, like start() and stop(). This makes queues perfect solution to me.
As you may know DispathQueue does not guaranteed to execute every task on the same thread. Which is quite stressful for me, as it may break my app.
I don't really like the idea to create NSThread and implement my own queue on it.
Are there any way to bind DispatchQueue to exact Thread? Maybe NSOperationQueue can be bound?
As Apple Documentation says:
When it comes to adding concurrency to an application, dispatch queues provide several advantages over threads. The most direct advantage is the simplicity of the work-queue programming model. With threads, you have to write code both for the work you want to perform and for the creation and management of the threads themselves. Dispatch queues let you focus on the work you actually want to perform without having to worry about the thread creation and management. Instead, the system handles all of the thread creation and management for you. The advantage is that the system is able to manage threads much more efficiently than any single application ever could. The system can scale the number of threads dynamically based on the available resources and current system conditions. In addition, the system is usually able to start running your task more quickly than you could if you created the thread yourself.
In simple words, you either work with dispatch queues, simply creating them and sending work to them, OR you work with NSThreads and NSRunLoops, creating them, setting them up, sending work to them, and possibly stopping them.
In detail:
NSThread / NSRunLoop
Creation:
self.thread = [[NSThread alloc] initWithTarget:self selector:#selector(threadMainRoutine) object:nil];
[self.thread start];
Start / management:
- (void)threadMainRoutine
{
// Set the runLoop variable, to signal this thread is alive
self.runLoop = [NSRunLoop currentRunLoop];
// Add a fake Mach port to the Run Loop, to avoid useless iterations of the main loop when the
// thread is just started (at this time there are no events added to the run loop, so it will
// exit immediately from its run() method)
[self.runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
//--- Thread main loop
while (thread_KeepRunning)
{
// Run the run loop. This function returns immediately if the RunLoop has nothing to do.
// NOTE: THIS STATEMENT:
// [self.runLoop run];
// DOES NOT WORK, although it is equivalent to CFRunLoopRun();
CFRunLoopRun();
}
// Unset the runLoop variable, to signal this thread is about to exit
self.runLoop = nil;
}
Adding work to be performed on it:
[self performSelector:#selector(mySelector:) onThread:myThread withObject:myObject waitUntilDone:YES];
Shutdown:
- (void)stop
{
if (self.thread) {
while (self.thread.isExecuting) {
thread_KeepRunning = NO;
CFRunLoopStop([self.runLoop getCFRunLoop]);
[NSThread sleepForTimeInterval:0.1f];
}
}
self.runLoop = nil;
self.thread = nil;
}
Dispatch Queue
Creation:
dispatch_queue_t myQueue = dispatch_queue_create("My Queue", DISPATCH_QUEUE_SERIAL);
Start:
dispatch_resume(myQueue);
Adding work to be performed on it:
dispatch_async(myQueue, (void)^ {
// put the work into this block
});
Shutdown:
dispatch_suspend(myQueue);
myQueue = nil;
In addition, Apple Documentation says that
Because Grand Central Dispatch manages the relationship between the tasks you provide and the threads on which those tasks run, you should generally avoid calling POSIX thread routines from your task code. If you do need to call them for some reason, you should be very careful about which routines you call
So: if you use dispatch queues, don't mess with threads.

How to find conflicting thread in frozen UI

I am having UI frozen/blocked due to semaphore_wait_trap in main thread.
When the UI is frozen, I pause using XCODE and the last two lines in stacktrace:
0x103f0ea30 <+809>: callq 0x103f1554d ; _dispatch_thread_semaphore_wait
dispatch_sync(someQueue, block); // this is my code.
How can I find what is causing the block?
Any other suggestion to find out what is causing the block?
It always blocks on the same line/code.
In the Debug navigator (cmd-6), you should have a list of threads. One OTHER thread in there should be waiting for someQueue as well. I can't think off hand of a case where that wasn't the case. Usually the two threads are waiting for each other, (e.g. via dispatch_sync).
For example, you might have this:
dispatch_sync(mySerialQueue, ^{
[self foo];
});
and
- (void)foo
{
dispatch_sync(mySerialQueue, ^{
...
});
}
The latter will be waiting for the former to finish forever, because the former is holding onto myQueue until it finishes the call to -foo.
(Note that mySerialQueue has to be created with the DISPATCH_QUEUE_SERIAL for this to happen.)

How to load page content within a new UIWebView before exiting current method

I have an application with implemented local server which handles request from web front-end.
UIWebView presents some GUI, user do some interaction, I handle his requests and send responses back to webview.
Sometimes I'm receiving some request which require to open second webview (e.g for facebook login) and wait in current method for results to return from that second webview.
When I'm running such case on iDevice with dual core processor it works as expected.
But when I'm running it on single core iPhone 4, webview processing is blocked until i leave the current method (white page with waiting indcator).
I solved this by putting sleep for current thread so the main thread will have time to process events in his run loop (if I properly understand this)
- (void)requestProcessingMethod { // <-- on background thread
someCalculations ...
dispatch_sync(dispatch_get_main_queue(), ^{
[self displayFacebookLoginWebView];
});
while(!facebookReturnCondition){
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
[NSThread sleepForTimeInterval:0.5]; // <-- on single core without this
// facebook webview will not load the login page
}
return response; //
}
I'm not happy with that. Setting thread for sleep looks like very poor solution.
Is there any way to add working UIWebView from background thread without exiting current method (background thread)?
Or is it possible to manually switch/force run loop execution?
Now I am not sure if this will work, can't test at the moment. But:
You could try having the operations as separate operations in a queue, using Operation Dependencies.
in your case when you use this method:
-(void)methodThatCallsRequestProcessingMethod {
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
NSInvocationOperation* theMainThreadOp = [[NSInvocationOperation alloc] initWithTarget:self
selector:#selector(displayFacebookLoginWebView) object:nil];
NSInvocationOperation* theOp = [[NSInvocationOperation alloc] initWithTarget:self
selector:#selector(requestProcessingMethod) object:nil];
[theOp addDependency: theMainThreadOp];
[[NSOperationQueue mainQueue] addOperation: theMainThreadOp];
[queue addOperation:theOp];
}
From reading the Concurrency Guide, it appears you can have operation dependencies over different queues. Which means that you can ensure the UI runs in the main thread, web later running in an async thread, keeping the Main Thread clear and responsive on all devices.
Apple Concurrency Guide

Resources