One thing that I do is:
-(void)GrabbingProcess:(void (^)())block;
{
self.OtherGrabbingIndicator +=1;
block();
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
self.OtherGrabbingIndicator -=1;
});
}
Everytime I want to run something that may take a long time in the background, I do something like
[Grabclass grab] GrabbingProcess: ^{
//Do something grab data etc.
}];
There are many such functions and many such data. For example, at first I would grab all the businesses ID. Then I would grab all the details on the businesses on separate thread.
I want to know a time when ALL those threads have finished and post a suitable notification.
The problem with my solution is that after a while, quite often the value of self.OtherGrabbingIndicator hover around 2 or 3 never going down even though all of those thread have finished.
Somehow some of the self.OtherGrabbingIndicator +=1; “leaked” and not matched with self.OtherGrabbingIndicator -=1. I wonder how can that leak ever happen?
If you want to run blocks asynchronously and then find out when they’re done, the appropriate tool is a
dispatch_group. You can dispatch blocks onto a specific group and queue usingdispatch_group_async(), and the group will track when the block is finished. You can then either wait synchronously on the group to finish withdispatch_group_wait()or register a block to be invoked when the group is done withdispatch_group_notify().The reason why your solution above doesn’t work is because you aren’t accessing/mutating the counter in a threadsafe way. Here’s a trivial series of events that will cause the problem:
Start: self.OtherGrabbingIndicator is 1
Thread A: reads self.OtherGrabbingIndicator
Thread B: reads self.OtherGrabbingIndicator
Thread A: increments the read value and writes back to self.OtherGrabbingIndicator
Thread B: increments the read value and writes back to self.OtherGrabbingIndicator
End: self.OtherGrabbingIndicator is 2
Even though two threads tried to increment it, only one “succeeded” and you end up losing the other increment. This can also happen during decrement. If you use dispatch groups this problem goes away.
As a side note, you should never use
dispatch_get_current_queue(). This is a debugging function that is never supposed to be used in actual code. The primary reason is because you aren’t just running on one queue, you’re running on a whole hierarchy of queues simultaneously, but this function can only tell you about the one queue. In addition, you may be running on someone’s private queue and you certainly should not be dispatching onto that yourself.