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.)
Related
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.
I've used both GCD and performSelectorOnMainThread:waitUntilDone in my apps, and tend to think of them as interchangeable--that is, performSelectorOnMainThread:waitUntilDone is an Obj-C wrapper to the GCD C syntax. I've been thinking of these two commands as equivalent:
dispatch_sync(dispatch_get_main_queue(), ^{ [self doit:YES]; });
[self performSelectorOnMainThread:#selector(doit:) withObject:YES waitUntilDone:YES];
Am I incorrect? That is, is there a difference of the performSelector* commands versus the GCD ones? I've read a lot of documentation on them, but have yet to see a definitive answer.
As Jacob points out, while they may appear the same, they are different things. In fact, there's a significant difference in the way that they handle sending actions to the main thread if you're already running on the main thread.
I ran into this recently, where I had a common method that sometimes was run from something on the main thread, sometimes not. In order to protect certain UI updates, I had been using -performSelectorOnMainThread: for them with no problems.
When I switched over to using dispatch_sync on the main queue, the application would deadlock whenever this method was run on the main queue. Reading the documentation on dispatch_sync, we see:
Calling this function and targeting
the current queue results in deadlock.
where for -performSelectorOnMainThread: we see
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.
I still prefer the elegance of GCD, the better compile-time checking it provides, and its greater flexibility regarding arguments, etc., so I made this little helper function to prevent deadlocks:
void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
if ([NSThread isMainThread])
{
block();
}
else
{
dispatch_sync(dispatch_get_main_queue(), block);
}
}
Update: In response to Dave Dribin pointing out the caveats section ondispatch_get_current_queue(), I've changed to using [NSThread isMainThread] in the above code.
I then use
runOnMainQueueWithoutDeadlocking(^{
//Do stuff
});
to perform the actions I need to secure on the main thread, without worrying about what thread the original method was executed on.
performSelectorOnMainThread: does not use GCD to send messages to objects on the main thread.
Here's how the documentation says the method is implemented:
- (void) performSelectorOnMainThread:(SEL) selector withObject:(id) obj waitUntilDone:(BOOL) wait {
[[NSRunLoop mainRunLoop] performSelector:selector target:self withObject:obj order:1 modes: NSRunLoopCommonModes];
}
And on performSelector:target:withObject:order:modes:, the documentation states:
This method sets up a timer to perform the aSelector message on the current thread’s run loop at the start of the next run loop iteration. The timer is configured to run in the modes specified by the modes parameter. When the timer fires, the thread attempts to dequeue the message from the run loop and perform the selector. It succeeds if the run loop is running and in one of the specified modes; otherwise, the timer waits until the run loop is in one of those modes.
GCD's way is suppose to be more efficient and easier to handle and is only available in iOS4 onwards whereas performSelector is supported in the older and newer iOS.
I have an app that uses a connection queue that handles the connections on a background thread. Each connection sends a JSON post, then when it receives a success, saves some objects into coredata.
Once all connections are complete, i call a dispatch_async on the main thread to call a finished method.
However, under very specific conditions of data im sending/saving, I've noticed the dispatch_async block to the main thread never gets called, and the app screen freezes, all execution stops, and the app sits idle with a frozen screen. processing power according to xcode is 0%.
Here is method with the block that fails.
- (void)connectionDidComplete
{
_completeConnections++;
_syncProgress = (float)_completeConnections / (float)_totalConnections;
dispatch_async(mainQueue, ^(void) {
[[NSNotificationCenter defaultCenter] postNotificationName:SyncQueueDidUpdateNotification object:nil];
}); <-- this dispatch works
if (_completeConnections == _totalConnections)
{
// clear unsynced data
NSArray *syncedObjects = [SyncObject completedSyncObjects];
if (syncedObjects.count > 0)
{
for (SyncObject *syncObject in syncedObjects)
{
[syncObject delete];
}
}
//this method saves the current context, then merges this context with the main context right after
[[VS_CoreDataManager sharedManager] saveManagedObjectContextAndWait:managedObjectContext];
// cleanup the thread's context
[[VS_CoreDataManager sharedManager] unRegisterManagedObjectContextForThread:currentThread];
managedObjectContext = nil;
// complete sync
dispatch_async(mainQueue, ^(void) {
[self performSelector:#selector(finishSync) withObject:nil afterDelay:2];
}); <-- this dispatch never gets called
}
}
My suspicion is this problem has something to do with saving the context then merging it. And possibly while that is happening its released in the middle of the merge, causing some weird hang up and the dispatch isn't getting executed. This is just a guess though, and I don't know how to fix it.
Any ideas?
Thanks.
If the block on the main thread is not executed, then it is because of 1 of 2 reasons.
The main thread is blocked; is not processing any events at all. Got a while() loop on the main thread? That'd do it. A lock? There you go.
The main thread is running a modal run loop inside the outer run loop. Asynchronous dispatches to the main event loop -- main thread -- won't be processed in this case.
Set a breakpoint on that dispatch_async() and see what the main thread is doing (at the point of dispatch the main thread is most likely already in the bad state).
DarkDust's suggestion of using dispatch_after() is a good one, but is unlikely to work in that it is almost assuredly the case that your main thread is not processing events when the problem occurs. I.e. fix the problem, then move to dispatch_after() as DarkDust suggests.
If your main thread is busy with modal runloop, then you could try
CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, block
});
I believe this is a great discussion. I came across this when I had the following code:
dispatch_synch(dispatch_get_main_queue()){
print("I am here")
}
the print code did not execute as I was dispatching a 'synch' block on the serial main thread which caused a dead lock. print was waiting for the dispatch to finish and dispatch was waiting for print to finish. When you dispatch in the main serial queue then you should use dispatch_async. and i guess if you use a concurrent queue then dispatch synch suits better
I created an NSOperation subclass to handle some zip archive operations. No matter what, if I override -start or -main this block of code always happens:
if ([NSThread isMainThread]) {
NSLog(#"I am in the main thread");
return;
}
Any idea what's going on?
I've tried adding this block:
- (void) start { //also tried overriding main
if ([NSThread isMainThread]) {
NSLog(#"In main thread, trying again");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self start];
});
return;
//hard working code etc...
//cpu intensive zip operations...
}
But this causes a crash, an EXC_BAD_ACCESS violation pointing at the dispatch_async line.
No matter what, if I override -start or -main this block of code always happens:
The main operation queue runs on the main thread. From the docs for +[NSOperationQueue mainQueue]:
The returned queue executes operations on the main thread. The main
thread’s run loop controls the execution times of these operations.
So, running in another thread is a matter of what queue you add the operation to, not how you write the operation's code. If you want your operation to run on a different operation queue, you'll need to create a queue of your own using
NSOperationQueue* aQueue = [[NSOperationQueue alloc] init];
You can find an example in Adding Operations to an Operation Queue in the Concurrency Programming Guide.
But this causes a crash, an EXC_BAD_ACCESS violation pointing at the dispatch_async line.
It sounds like -[NSOperation start] probably isn't re-entrant. Your code effectively executes the same method on two different threads. In fact, look at the docs for -start, it's obvious that your code won't work:
You can call this method explicitly if you want to execute your
operations manually. However, it is a programmer error to call this
method on an operation object that is already in an operation queue
or to queue the operation after calling this method. Once you add an
operation object to a queue, the queue assumes all responsibility for
it. [Emphasis added. -Caleb]
In other words, don't do that.
On iOS device, I recently found that a strange behavior.
Code1:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(#"1111");
});
while (1) {
sleep(1);
}
});
Code2:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(#"1111");
});
while (1) {
sleep(0.5);
}
});
Code1 and Code2's only difference is that Code1 sleep 1second every loop and Code2 sleep 0.5.
If you run these two code on iOS device with single core, Code1 will print out the #"1111", but Code2 won't.
I don't why, the global queue is assumed to be concurrent.It should always print out the number no matter what other blocks are doing. And if it is something due to that single core device's limit, why sleep(0.5) and sleep(1) would make the difference?
I really want to know the reason for this.
EDIT
I found use sleep(0.5) is my stupid mistake. sleep() function take an unsigned int parameter.So sleep(0.5) is equal to sleep(0). But do sleep(0) will block the whole concurrent queue?
The reason is that your second sleep() is essentially a sleep(0) which means that you're now buzz-looping the thread that GCD gave to you, and that's probably the same thread that would have executed the nested dispatch_async() if you had given it a chance to do anything else, which the first example does. During the one second sleep, GCD sees that the thread is blocked and creates a new one to service the outstanding queued request(s). In the second example, you're essentially computationally starving the enqueued work - GCD is not smart enough to know that a thread has been locked into an infinite loop, and you're not giving the system enough work to justify (in GCD's eyes) the creation of another thread, so... You've essentially discovered a bug in GCD's low-threshold of work logic, I think.
Just checked out, 1st and 2nd snippets print "1111".
Note, nesting of dispatch_async you use won't give any profit, because you set the same priorities (DISPATCH_QUEUE_PRIORITY_DEFAULT) all the tasks "NSLog(#"1111");"
and "
while (1) {
sleep(0.5);
"
will be added to the same target queue. As the result I can assume that in the first case block with WHILE will be executed first, and because it will not finish never, the next task in the queue(NSLog(...)) will be never called.
You can try to use different priorities for the queues (DISPATCH_QUEUE_PRIORITY_LOW f.e.).