make a simple NSInteger counter thread safe - ios

I define a NSInteger counter and updated its value in a callback like the following code shows (callback is in another thread):
-(void) myFunc {
NSLog(#"initialise counter...");
// I try to use volatile to make it thread safe
__block volatile NSInteger counter = 0;
[self addObserver:myObserver withCallback:^{
// this is in another thread
counter += 1;
NSLog(#"counter = %d", counter);
}];
}
I use volatile keyword to make the counter thread safe, it is accessed in a callback block which belongs to another thread.
When I invoke myFunc two times:
// 1st time call
[self myFunc];
// 2nd time call
[self myFunc];
the output is like this:
initialise counter...
counter = 1;
counter = 2;
counter = 3;
counter = 4;
counter = 1; // weird
initialise counter...
counter = 2; // weird
counter = 3;
counter = 1; // weird
counter = 4;
It looks like the 2nd time call produce a counter with wrong initial value, and the output before counter=4 is counter=1 which is also weird.
Is it because my code is not thread safe even with volatile keyword? If so, how to make my counter thread safe? If it is thread safe, why I get weird output?

For the simple case of an atomic counter, GCD is overkill. Use the OSAtomic functions:
-(void) myFunc {
static int64_t counter;
[self addObserver:myObserver withCallback:^{
// this is in another thread
int64_t my_value = OSAtomicIncrement64Barrier(&counter);
NSLog(#"counter = %d", my_value);
}];
}
Note that the code logs the result of the increment function rather than the static variable. The result gives you the atomic result of your specific operation. Using the static variable would give you a snapshot of the counter that's not atomic with respect to your increment operation.

First of all using a local variable is corrupted. It will be removed from stack, when the function returns. Therefore the block copies the variable's value (capture) when the block definition is executed (counter = 0) and works on the copy.
If you have a shared resource as the counter is, you have to put accesses to it into a block.
// global
dispatch_queue_t counterQueue;
int counter;
// initialize
counterQueue = dispatch_queue_create( "com.yourname.counterQueue", DISPATCH_QUEUE_SERIAL);
counter = 0;
// Whenever you read or write to counter
dispatch_async( counterQueue,
^{
counter++;
NSLog( #"%d", counter" );
}
// or
int lastValue;
dispatch_sync( counterQueue,
^{
lastValue = counter;
}
// Do something with it.

There are lots of things wrong with your code. It looks like you're calling myFunc repeatedly. Each time you do, it creates a new instance of the counter.
Make your counter an instance variable or app-wide global.
A simple way to make incrementing (and logging) the counter thread-safe is to make the body of the observer use dispatch_async(dispatch_get_main_queue()<your code here>). That way the code that messes with the counter always runs on the main thread, even if it's called from other threads. This isn't the most performant way to handle it, but it's easy.
Otherwise you're going to need to use locks or some other concurrency technique. That requires a strong understanding of thread safety, which your post, frankly, shows that you don't have. (Not to be mean, it's one of the more difficult subjects in computing.)
EDIT:
As Avi points out in his comment, using the main queue to manage the counter would cause the other threads to block waiting on the main thread, and is not a very good solution. (It would work, but would take away just about all the performance benefit of using multiple threads)
It would be better to set up a single serial queue and make that a lazily loaded property of the object that manages this counter, protected with dispatch_once(). However, I don't have enough coffee on-board to write out that code in a forum post.

Related

iOS Why wouldn't exiting a method in the main thread from a sub-thread work?

I'm initiating an asynch thread using grand central dispatch in objective-c using the following code:
dispatch_queue_t myQueue = dispatch_queue_create("My Queue",NULL);
dispatch_async(myQueue, ^{
}
For a very long time I was having trouble correctly exiting the IBAction that triggers this. I do a lot of the code in the main thread wrapped inside this GCD thread using this code:
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}
What I originally tried to do was simply put the return; statement inside this mainQueue block. After a lot of fiddling I discovered that to break out of the IBAction that contains all this the return; needs to be in the GCD queue.
Why is this? I thought that return would exit methods regardless of where it is in the program. Also, is it even possible to exit from a nested queue call like this?
A block is similar to a function. It is a different context from the code which defines it. A return statement within a block exits that block, not the method or function within which the block was defined. (If the block has a non-void return type, the return statement also gives the return value of the block.)
For example, consider:
void foo(void)
{
int (^block)(int, int) = ^int(int a, int b) { return a + b; }
printf("3 + 5 = %d\n", block(3, 5));
}
The return statement in the block does not return from foo(), it just returns from the block and gives the return value of the block. The block is like a little separate function except that its code is provided right in the middle of another function and it can capture local variables from the context of its definition.
Now, the block given to dispatch_async() does not take arguments or return a value, but the flow control of the return statement is the same. It returns from that block, not from the method or function containing the call to dispatch_async(). In particular, since dispatch_async() runs the block asynchronously, it is quite possible (even likely) that the block won't be run until well after the method or function that called dispatch_async() has already exited.

Idiomatic way to execute an array of blocks

I have an object that can execute an arbitrary queue of updates. I use blocks to embody the updates. I add an update using my addUpdate: method.
- (void) addUpdate: (void(^)())block {
[self.updates addObject: block];
}
Later, I want to execute all of them. I don't care if they run concurrently or not. The basic primitive way would seem to be something like:
for (NSUInteger index = 0; index < self.updates.count; index++) {
void (^block)() = self.updates[index];
block();
}
or with fast enumeration
for (void (^block)() in self.updates) {
block();
}
Or is there something I should be doing with GCD to make this happen?
The most terse way I can think of to do this would be:
[self.updates makeObjectsPerformSelector: #selector(invoke)];
How "idiomatic" that is will probably be situation-dependent...
EDIT: This depends on the fact that blocks are implemented in the runtime as Objective-C objects, and respond to the selector -invoke. In other words, the expression block(); can also be expressed as [block invoke];. I'm not aware of any more succinct way to execute an array of blocks.
For non-concurrent execution, for-in is the way to go. For concurrent execution, you could use NSArray's -enumerateUsing... methods and pass the concurrent flag, or use dispatch_apply() instead of a loop.

Incorrect decrement of the reference count of an object that is not owned at this point by the caller using dispatch_release

I am trying to use tonymillion reachabiity libaray however I am getting an error in part of the code that releases the items in the que.
This is what the error looks like Incorrect decrement of the reference count of an object that is not owned at this point by the caller
this is what my code looks like
//create a serial queue
self.reachabilitySerialQueue = dispatch_queue_create("com.tonymillion.reachability", NULL);
// set it as our reachability queue which will retain the queue
if(SCNetworkReachabilitySetDispatchQueue(self.reachabilityRef, self.reachabilitySerialQueue))
{
dispatch_release(self.reachabilitySerialQueue); //error here
// refcount should be ++ from the above function so this -- will mean its still 1
return YES;
}
dispatch_release(self.reachabilitySerialQueue); // error here
self.reachabilitySerialQueue = nil;
return NO;
I am not sure how else to get around this and was hoping someone could provide some insight as my experiance with refrence counting is very thin.
any help would be appreicated.

UI is not updating while some function takes time to execution?

I am doing some image processing and with this also showing the loading. Problem is that loading is not updating.
for (ALAsset *asset in assets) {
weakSelf.HUD.labelText = [NSString stringWithFormat:#"%d/%d",count,assets.coun
weakSelf.HUD.progress=(CGFloat)count/assets.count;
[objDoc setImageProcess:asset];
count++;
}
Here the HUD is not updating its value. If I put the delay then its showing. Here setImageProcess takes time while processing.
UI updates take place on the main thread in iOS and Mac OS. If you have time-consuming code that runs on a background thread, you can send messages to the main thread to update the UI and it works perfectly.
If you are running your time-consuming code on the main thread, UI changes get accumulated, and only get rendered to the screen when your app returns and visits the event loop.
So, if you have a loop that does a bunch of time-consuming tasks and doesn't return until the whole loop is finished, it doesn't work because the UI updates don't take place until you return.
You need to refactor your code to return between iterations. Something like this:
Create an instance variable assetCount:
#interface myClass: UIViewController;
{
NSInteger assetIndex;
}
#end.
Then
-(void) viewDidLoad;
{
assetIndex = 0;
[self processAssets];
}
- (void) processAssets;
{
if (assetIndex >= assets.count)
return;
ALAsset *asset = assets[assetIndex];
weakSelf.HUD.labelText = [NSString stringWithFormat:#"%d/%d",count,assets.coun
weakSelf.HUD.progress=(CGFloat)count/assets.count;
[objDoc setImageProcess:asset];
assetIndex++;
count++;
//The following method call queues up a method call
//for the next time your app visits the event loop. (plus an optional delay)
[self performsSelector: processAssets
withObject: nil
afterDelay: 0];
}
The method above processes 1 asset, then queues a delayed call to itself. Even though the delay value is 0 it still fixes your problem. That's because the performSelector:withObject:afterDelay: method always returns immediately, and queues up the method call for the next pass through the event loop. In the next pass through the event loop, the system does housekeeping like updating the screen, then checks for pending calls like this one. If there is a delay it will start a timer. If not, it will trigger your method call.
You have a variable count in the code you posted that might work as an array index. I added a new instance variable assetIndex to track the current array index. Your code also uses the term weakSelf, suggesting that this code is being executed from a block. It might be that there is a cleaner way to handle this, but you would need to provide more information.
For all UI changes, you have to call in mainthread. Verify that the current functions is called in main thread:
BOOL isMainThread = [[NSThread currentThread] isMainThread]

Difference between DART Isolate and Thread (Java,C#)

For me The DART Isolate looks like a Thread (Java/C#) with a different terminology. In which aspect Isolate differs from a Thread?
Threads use shared memory, isolates don't.
For example, the following pseudocode in Java/C#
class MyClass {
static int count = 0;
}
// Thread 1:
MyClass.count++;
print(MyClass.count); // 1;
// Thread 2:
MyClass.count++;
print(MyClass.count); // 2;
This also runs the risk of the shared memory being modified simultaneously by both threads.
Whereas in Dart,
class MyClass {
static int count = 0;
}
// Isolate 1:
MyClass.count++;
print(MyClass.count); // 1;
// Isolate 2:
MyClass.count++;
print(MyClass.count); // 1;
Isolates are isolated from each other. The only way to communicate between them is to pass messages. One isolate can listen for callbacks from the other.
Check out the docs here including the "isolate concepts" section.

Resources