Protecting critical code from being called again - objective-c

I need to protect a critical area of my code, which is multi-threaded. I want to prevent it from being called multiple times before the other thread is finished. This is what I am working with:
- (void) filterAllEventsIntoDictionary{
// start critical area
if (self.sortedKeys.count != 0) {
[self.sortedKeys removeAllObjects];
}
dispatch_async(self.filterMainQueue, ^{
[self internal_filterAllEventsIntoDictionary];
dispatch_sync(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
});
}
Since the internal_filterAllEventsIntoDictionary method also accesses self.sortedKeys, if this code is called twice, it crashes because of removeAllObjects at the start.
I still need to call the internal... method in another thread since I don't want to block the UI. So what's the best way to block on the start of this method while the dispatch_async call is still not finished?

While I am far from being a concurrency expert, it sounds to me like you need a lock on your sortedKeys object. If you used a traditional lock, though, you'd end up blocking the main thread.
The recommended replacement for locks in the world of Grand Central Dispatch is to put critical sections of code on a serial queue. See "Eliminating Lock-Based Code" in the Concurrency Programming Guide.
If you put the [self.sortedKeys removeAllObjects]; call onto the same queue that the block with the internal... call is scheduled on, you guarantee that it won't happen until after that block completes:
// start critical area
dispatch_async(self.filterMainQueue, ^{
if (self.sortedKeys.count != 0) {
[self.sortedKeys removeAllObjects];
}
});
This assumes that filterMainQueue is serial. Using dispatch_async for the critical section ensures that the main thread will not be blocked. Also note the warning in "Dispatch Queues and Thread Safety":
Do not call the dispatch_sync function from a task that is executing on the same queue that you pass to your function call. Doing so will deadlock the queue.
Although this will only be an issue if the internal... method does something that causes this method to be called again.

Related

dispatch_async doesn't fire until returned parent thread returns?

My Question is - Does dispatch_async fire immediately? I'm seeing that the creating thread has to return before dispatch_async fires.
My issue is that I am trying to make a async call to a 3rd party library appear to be synchronous. I know, I know... I should allow these async operations run as intended but I'm trying to do this way down in a complex multi-threaded operation and I really don't have a choice.
here's what starts the async call
-(void)connect
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0) , ^{
[device connect];
});
while(!connectCompleted)
{
NSLog(#"Sleeping..");
[NSThread sleepForTimeInterval:1.0];
}
}
and here's the delegate function that gets called AFTER the [device connect] successfully connects:
- (void)didConnect:(BXPrinterController *)controller
printer:(BXPrinter *)printer
{
connectCompleted = YES;
NSLog(#"didConnect");
}
with that dispatch_async wrapped around [device connect] the delegate never gets fired;
Does dispatch_async fire immediately
Of course not! That is what async means! The whole basis of the concept "asynchronous" (which is what async stands for) is that this is code that runs at some future unspecified time. Meanwhile the code that calls dispatch_async continues on to its end without waiting.
If for whatever reason you must make a call appear synchronous, I'd recommend that you first implement it synchronously (because you'll end up doing that anyway if people had enough of delays), and then you write a helper method that is synchronous:
Step 1: Create a dispatch_semaphore_t.
Step 2: Start the asynchronous code, with every code path ending by sending a signal to the dispatch_semaphore_t.
Step 3: Send a wait to the dispatch_semaphore_t. It wakes up, with no CPU time spent on it at all, just when the asynchronous code finishes.

Waiting for asynchronous threads in objective-c

I am trying to wait for asynchronous threads in objective-c without blocking the UI thread (it is an app).
I have the following code:
-(void)MainUIThread
{
[exporter exportAsynchronouslyWithCompletionHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
[self exportDidFinish:exporter];
//wait here without blocking
});
}];
}
In C# I would use async and await, can I easily achieve this in objective-c?
[exporter exportAsynchronouslyWithCompletionHandler:^{
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
[self exportDidFinish:exporter]; // Its non blocking process
dispatch_async(dispatch_get_main_queue(), ^(void){
//Update your UI.
});
}];
Try above snippet.
You calling [self exportDidFinish:exporter] method on main thread that why it block your UI. I suppose exportDidFinish method have just a business logic then post that logic calculation in background thread using dispatch_get_global_queue then get it back on main thread using dispatch_get_main_queue().
What makes you think that you should wait for an asynchronous operation to finish? That's the whole point of asynchronous operation, you don't wait for it!
You called exportAsynchronouslyWithCompletionHandler and gave it a block. I don't know that method, but I assume it will do things asynchronously, and when it is finished it will call the block that you give it. The call to exportAsynchronouslyWithCompletionHandler will return very quickly, as soon as the method has set up its asynchronous operation.
That block dispatches another block calling "exportDidFinish:exporter" on the main thread, then it returns (with no reason to wait), then all the asynchronous code in exportAsynchronouslyWithCompletionHandler is finished.
All we have now is one block dispatched to the main queue. As soon as the run loop is idle, that block is executed on the main thread. The commented line that you added "// Wait here" is pointless. exportDidFinish:exporter will be called on the main thread when it's time to be called, and then we are done.

Locked up waiting for #synchronized

I have this (rare) odd case where my objective-c iOS program is locking up. When I break into the debugger, there are two threads and both of them are stuck at a #synchronized().
Unless I am completely misunderstanding #synchronized, I didn't think that was possible and the whole point of the command.
I have a main thread and worker thread that both need access to a sqlite database, so I wrap the chunks of code that are accessing the db in #synchronized(myDatabase) blocks. Not much else happens in these blocks except the db access.
I'm also using the FMDatabase framework to access sqlite, I don't know if that matters.
The myDatabase is a global variable that contains the FMDatabase object. It is created once at the start of the program.
I know I'm late to the party with this, but I've found a strange combination of circumstances that #synchronized handles poorly and is probably responsible for your problem. I don't have a solution to it, besides to change the code to eliminate the cause once you know what it is.
I will be using this code below to demonstrate.
- (int)getNumberEight {
#synchronized(_lockObject) {
// Point A
return 8;
}
}
- (void)printEight {
#synchronized(_lockObject) {
// Point B
NSLog(#"%d", [self getNumberEight]);
}
}
- (void)printSomethingElse {
#synchronized(_lockObject) {
// Point C
NSLog(#"Something Else.");
}
}
Generally, #synchronized is a recursively-safe lock. As such, calling [self printEight] is ok and will not cause deadlocks. What I've found is an exception to that rule. The following series of events will cause deadlock and is extremely difficult to track down.
Thread 1 enters -printEight and acquires the lock.
Thread 2 enters -printSomethingElse and attempts to acquire the lock. The lock is held by Thread 1, so it is enqueued to wait until the lock is available and blocks.
Thread 1 enter -getNumberEight and attempts to acquire the lock. The lock is held already and someone else is in the queue to get it next, so Thread 1 blocks. Deadlock.
It appears that this functionality is an unintended consequence of the desire to bound starvation when using #synchronized. The lock is only recursively safe when no other thread is waiting for it.
The next time you hit deadlock in your code, examine the call stacks on each thread to see if either of the deadlocked threads already holds the lock. In the sample code above, by adding long sleeps at Point A, B, and C, the deadlock can be recreated with almost 100% consistency.
EDIT:
I'm no longer able to demonstrate the previous issue, but there is a related situation that still causes issues. It has to do with the dynamic behavior of dispatch_sync.
In this code, there are two attempts to acquire the lock recursively. The first calls from the main queue into a background queue. The second calls from the background queue into the main queue.
What causes the difference in behavior is the distinction between dispatch queues and threads. The first example calls onto a different queue, but never changes threads, so the recursive mutex is acquired. The second changes threads when it changes queues, so the recursive mutex cannot be acquired.
To emphasize, this functionality is by design, but it behavior may be unexpected to some that do not understand GCD as well as they could.
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSObject *lock = [[NSObject alloc] init];
NSTimeInterval delay = 5;
NSLog(#"Example 1:");
dispatch_async(queue, ^{
NSLog(#"Starting %d seconds of runloop for example 1.", (int)delay);
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:delay]];
NSLog(#"Finished executing runloop for example 1.");
});
NSLog(#"Acquiring initial Lock.");
#synchronized(lock) {
NSLog(#"Acquiring recursive Lock.");
dispatch_sync(queue, ^{
NSLog(#"Deadlock?");
#synchronized(lock) {
NSLog(#"No Deadlock!");
}
});
}
NSLog(#"\n\nSleeping to clean up.\n\n");
sleep(delay);
NSLog(#"Example 2:");
dispatch_async(queue, ^{
NSLog(#"Acquiring initial Lock.");
#synchronized(lock) {
NSLog(#"Acquiring recursive Lock.");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(#"Deadlock?");
#synchronized(lock) {
NSLog(#"Deadlock!");
}
});
}
});
NSLog(#"Starting %d seconds of runloop for example 2.", (int)delay);
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:delay]];
NSLog(#"Finished executing runloop for example 2.");
I stumbled into this recently, assuming that #synchronized(_dataLock) does what it's supposed to do, since it is such a fundamental thing after all.
I went on investigating the _dataLock object, in my design I have several Database objects that will do their locking independently so I was simply creating _dataLock = [[NSNumber numberWithInt:1] retain] for each instance of Database.
However the [NSNumber numberWithInt:1] returns the same object, as in same pointer!!!
Which means what I thought was a localized lock for only one instance of Database is not a global lock for all instances of Database.
Of course this was never the intended design and I am sure this was the cause of issues.
I will change the
_dataLock = [[NSNumber numberWithInt:1] retain]
with
_dataLock = [[NSUUID UUID] UUIDString] retain]

UI does not update when main thread is blocked in Cocoa app

I am using a NSProgressIndicator in my main thread to update on progress as I run through my entire method. Now when I end up calling an object from a different class file, and wait for that object to return to a value to my main thread, I notice that the NSProgressIndicator will disappear. I understand that this is because the main thread is blocked until I get the return value from the other object.
So my questions is what is the recommended way for updating UI in the main thread without blocking it and having other objects run in the background and return values to the main thread as needed. I know how to use blocks but blockoperations are not allowed to return values.
What I need is something that helps this pseudo code:
-(IBAction) main {
//Update progress indicator UI to show progress
//perform an call to another object from another class.
// wait till i get its return value.
//Update progress indicator UI to show progress
// Use this return value to do something.
//Update progress indicator UI to show progress
}
When the call to the other object is made, I notice that the determinate NSProgressIndicator I have completely disappears since the main thread is blocked. Thanks.
Your above code is not the correct approach. Since main never returns, the progress indicator will never update. You must return quickly on the main thread.
Instead, what you want to do is set up a background block that at various points updates the progress indicator on the main thread. So, for instance:
- (IBAction)start:(id)sender {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{[self.progress setProgress:0];});
// Doing some stuff
dispatch_async(dispatch_get_main_queue(), ^{[self.progress setProgress:.25];});
// Doing more stuff
dispatch_async(dispatch_get_main_queue(), ^{[self.progress setProgress:.75];});
});
}
(Yes, this causes the queue to retain self, but that's ok here because self is not retaining the queue.)
You can achieve what you are looking for with GCD (Grand Central Dispatch).
Here is an example to get you started:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^{
// Perform async operation
dispatch_sync(dispatch_get_main_queue(), ^{
// Update UI
});
});
It sounds like your operation should be run in a separate thread which can be done several ways but is probably most easily achieved using NSOperationQueue and either custom NSOperation classes (it's easier than it sounds to set these up) or use of the NSInvokeOperation class.
Then you can send messages back to your class in the main thread using the NSNotificationCenter or set up as an observer using Key-Value Observing (KVO).
Bottom line, you have a variety of choices and to make the best one should have an understanding of the underlying technologies. I'd start with Apple's Threaded Programming Guide personally, then read it a second time to be sure you extracted all the goodness before building out your solution.

dispatch_sync on main queue hangs in unit test

I was having some trouble unit testing some grand central dispatch code with the built in Xcode unit testing framework, SenTestingKit. I managed to boil my problem done to this. I have a unit test that builds a block and tries to execute it on the main thread. However, the block is never actually executed, so the test hangs because it's a synchronous dispatch.
- (void)testSample {
dispatch_sync(dispatch_get_main_queue(), ^(void) {
NSLog(#"on main thread!");
});
STFail(#"FAIL!");
}
What is it about the testing environment that causes this to hang?
dispatch_sync runs a block on a given queue and waits for it to complete. In this case, the queue is the main dispatch queue. The main queue runs all its operations on the main thread, in FIFO (first-in-first-out) order. That means that whenever you call dispatch_sync, your new block will be put at the end of the line, and won't run until everything else before it in the queue is done.
The problem here is that the block you just enqueued is at the end of the line waiting to run on the main thread—while the testSample method is currently running on the main thread. The block at the end of the queue can't get access to the main thread until the current method (itself) finishes using the main thread. However dispatch_sync means Submits a block object for execution on a dispatch queue and waits until that block completes.
The problem in your code is that no matter whether you use dispatch_sync or dispatch_async , STFail() will always be called, causing your test to fail.
More importantly, as BJ Homer's explained, if you need to run something synchronously in the main queue, you must make sure you are not in the main queue or a dead-lock will happen. If you are in the main queue you can simply run the block as a regular function.
Hope this helps:
- (void)testSample {
__block BOOL didRunBlock = NO;
void (^yourBlock)(void) = ^(void) {
NSLog(#"on main queue!");
// Probably you want to do more checks here...
didRunBlock = YES;
};
// 2012/12/05 Note: dispatch_get_current_queue() function has been
// deprecated starting in iOS6 and OSX10.8. Docs clearly state they
// should be used only for debugging/testing. Luckily this is our case :)
dispatch_queue_t currentQueue = dispatch_get_current_queue();
dispatch_queue_t mainQueue = dispatch_get_main_queue();
if (currentQueue == mainQueue) {
blockInTheMainThread();
} else {
dispatch_sync(mainQueue, yourBlock);
}
STAssertEquals(YES, didRunBlock, #"FAIL!");
}
If you are on the main queue and synchronously wait for the main queue to be available you will indeed wait a long time. You should test to make sure you are not already on the main thread.
Will you ever get out of house if you must wait for yourself to get out house first? You guessed right! No! :]
Basically if:
You are on FooQueue. (doesn't have to be main_queue)
You call the method using sync ie in a serial way and want to execute on FooQueue.
It will never happen for same reason that you will never get out of house!
It won't ever get dispatched because it's waiting for itself to get off the queue!
To follow up, since
dispatch_get_current_queue()
is now deprecated, you can use
[NSThread isMainThread]
to see if you are on the main thread.
So, using the other answer above, you could do:
- (void)testSample
{
BOOL __block didRunBlock = NO;
void (^yourBlock)(void) = ^(void) {
NSLog(#"on main queue!");
didRunBlock = YES;
};
if ([NSThread isMainThread])
yourBlock();
else
dispatch_sync(dispatch_get_main_queue(), yourBlock);
STAssertEquals(YES, didRunBlock, #"FAIL!");
}