NSLock, number of threads waiting - ios

I'm developing an iOS app and need to implement a solution for a problem for which I need to know how many threads are waiting for locking the same NSLock object.
In Java I have the class ReentrantLock, with the method getQueueLength, which "Returns an estimate of the number of threads waiting to acquire this lock."
Is there something similar in Objective-C? I've tried to find something, but nothing. Should I subclass NSLock for implementing this mechanism by myself?

Look at OSAtomic.h. You can create a global counter, then before a thread tries to get the lock increment it, then decrement afterwards. To read the current value you "add" 0 to it and look at the return value. I have used these for years on both OSX and ios.

You can create a subclass of NSLock with the same functionality by overriding the lock, unlock and tryLock methods.
Example:
#interface ReentrantLock : NSLock
#property (atomic) NSInteger numberOfThreads;
- (void)lock;
- (void)unlock;
- (BOOL)tryLock;
#end
#implementation ReentrantLock
- (void)lock {
self.numberOfThreads += 1;
[super lock];
}
- (void)unlock {
self.numberOfThreads -= 1;
[super unlock];
}
- (BOOL)tryLock {
self.numberOfThreads += 1;
return [super tryLock];
}
#end

Related

Timestamp / NSDate for current event start in UIKit

Question:
How can I make sure that the code executed due to a runloop event (timer, user interaction, performSelector, etc) have the same concept of "now"?
Background:
Say that event handler takes 100ms to execute, that means that [NSDate date] will return a slightly different "now" depending on when in the execution you make the call. If you are very unlucky with the timing you might even end up with different dates between the calls.
This creates problems for things that rely on the current time for doing various calculations since those calculations can differ during the execution.
Of course, for a specific event handler you could just store the date in the AppDelegate or similar or pass it on in each call starting from the entry point.
However, I want something safer and automatic. Ideally I want to know at what time the current run loop started processing the event. Something I can simply replace [NSDate date] with and always get the same result until the next event is fired.
I looked into the documentation of NSRunLoop without much luck. I also looked into CADisplayLink for potential workarounds. Neither provided a clear cut answer.
It feels like this should be a common thing to need, not something that needs "workarounds". My guess is that I am looking in the wrong places or using the wrong search terms.
Code Example:
UIView *_foo, _fie;
NSDate *_hideDate;
- (void)handleTimer
{
[self checkVisible:_foo];
[self checkVisible:_fie];
}
- (void)checkVisible:(UIView *)view
{
view.hidden = [_hideDate timeIntervalSinceNow] < 0];
}
In this case we could end up with _fie being hidden when _foo is still visible since "now" has changed by a very small amount between calls.
This is a very simplified example in which a fix is trivial by simply calling [NSDate date] and sending that instance to all callers. It is the general case that I am interested in though where call chains might be very deep, cyclic, re-entrant, etc.
NSRunLoop is a wrapper for CFRunLoop. CFRunLoop has features that NSRunLoop doesn't expose, so sometimes you have to drop down to the CF level.
One such feature is observers, which are callbacks you can register to be called when the run loop enters different phases. The phase you want in this case is an after-waiting observer, which is called after the run loop receives an event (from a source, or due to a timer firing, or due to a block being added to the main queue).
Let's add a wakeDate property to NSRunLoop:
// NSRunLoop+wakeDate.h
#import <Foundation/Foundation.h>
#interface NSRunLoop (wakeDate)
#property (nonatomic, strong, readonly) NSDate *wakeDate;
#end
With this category, we can ask an NSRunLoop for its wakeDate property any time we want, for example like this:
#import "AppDelegate.h"
#import "NSRunLoop+wakeDate.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSTimer *timer = [NSTimer timerWithTimeInterval:0.5 repeats:YES block:^(NSTimer *timer){
NSLog(#"timer: %.6f", NSRunLoop.currentRunLoop.wakeDate.timeIntervalSinceReferenceDate);
}];
[NSRunLoop.currentRunLoop addTimer:timer forMode:NSRunLoopCommonModes];
return YES;
}
#end
To implement this property, we'll create a WakeDateRecord class that we can attach to the run loop as an associated object:
// NSRunLoop+wakeDate.m
#import "NSRunLoop+wakeDate.h"
#import <objc/runtime.h>
#interface WakeDateRecord: NSObject
#property (nonatomic, strong) NSDate *date;
- (instancetype)initWithRunLoop:(NSRunLoop *)runLoop;
#end
static const void *wakeDateRecordKey = &wakeDateRecordKey;
#implementation NSRunLoop (wakeDate)
- (NSDate *)wakeDate {
WakeDateRecord *record = objc_getAssociatedObject(self, wakeDateRecordKey);
if (record == nil) {
record = [[WakeDateRecord alloc] initWithRunLoop:self];
objc_setAssociatedObject(self, wakeDateRecordKey, record, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return record.date;
}
#end
The run loop can run in different modes, and although there are a small number of common modes, new modes can in theory be created on the fly. If you want an observer to be called in a particular mode, you have to register it for that mode. So, to ensure that the reported date is always correct, we'll remember not just the date but also the mode in which we recorded the date:
#implementation WakeDateRecord {
NSRunLoop *_runLoop;
NSRunLoopMode _dateMode;
NSDate *_date;
CFRunLoopObserverRef _observer;
}
To initialize, we just store the run loop and create the observer:
- (instancetype)initWithRunLoop:(NSRunLoop *)runLoop {
if (self = [super init]) {
_runLoop = runLoop;
_observer = CFRunLoopObserverCreateWithHandler(nil, kCFRunLoopEntry | kCFRunLoopAfterWaiting, true, -2000000, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
[self setDate];
});
}
return self;
}
When asked for the date, we first check whether the current mode is different from the date in which we recorded the mode. If so, then the date wasn't updated when the run loop awoke in the current mode. That means the observer wasn't registered for the current mode, so we should register it now and update the date now:
- (NSDate *)date {
NSRunLoopMode mode = _runLoop.currentMode;
if (![_dateMode isEqualToString:mode]) {
// My observer didn't run when the run loop awoke in this mode, so it must not be registered in this mode yet.
NSLog(#"debug: WakeDateRecord registering in mode %#", mode);
CFRunLoopAddObserver(_runLoop.getCFRunLoop, _observer, (__bridge CFRunLoopMode)mode);
[self setDate];
}
return _date;
}
When we update the date, we also need to update the stored mode:
- (void)setDate {
_date = [NSDate date];
_dateMode = _runLoop.currentMode;
}
#end
An important warning about this solution: the observer fires once per pass through the run loop. The run loop can service multiple timers and multiple blocks added to the main queue during a single pass. All of the serviced timers or blocks will see the same wakeDate.

How can I unit test a method that depends on a volatile variable in Objective-C?

Here's a simplified version of my class:
#interface RTMovieBuilder : NSObject
#property (atomic, getter = isCancelled) volatile BOOL cancelled;
#property (nonatomic, weak) id<BuilderDelegate>delegate;
- (void)moviesFromJSON:(id)JSON;
- (Movie *)movieFromDictionary:(NSDictionary *)dict;
- (void)cancel;
#end
#implementation RTMovieBuilder
- (void)moviesFromJSON:(id)JSON
{
// Check for errors -> If good, then do...
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
[self syncrouslyCreateMoviesFromJSON:JSON];
});
}
- (void)syncrouslyCreateMoviesFromJSON:(id)JSON
{
NSMutableArray *movies = [NSMutableArray array];
for (NSDictionary *dict in JSON)
{
if ([self isCancelled])
return;
else
[movies addObject:[self movieFromDictionary:dict]];
}
[self notifyDelegateCreatedObjects:movies];
}
- (Movie *)movieFromDictionary:(NSDictionary *)dict
{
Movie *movie = [[Movie alloc] init];
// Set movie properties based on dictionary...
return movie;
}
- (void)cancel
{
[self setCancelled:YES];
}
// ... Other methods omitted for brevity's sake
#end
The property cancelled is atomic and volatile because it may be accessed by other threads (i.e. the main thread may call cancel method to stop the operation). (I believe these are needed, if not, please note why it's not in your answer.)
I am trying to write unit tests to make sure this will work before writing the view controller class.
How can I write a unit test that will simulate a call to cancel while RTMovieBuilder is in the middle of creating movies?
Edit
Here's a unit test I have already written which tests to make sure that notifyDelegateCreatedObjects: isn't called if cancel is called first.
- (void)testIfCancelledDoesntNotifyDelegateOfSuccess
{
// given
RTMovieBuilder *builder = [[RTMovieBuilder alloc] init];
builder.delegate = mockProtocol(#protocol(BuilderDelegate));
// when
[builder cancel];
[builder notifyDelegateCreatedObjects:#[]];
// then
[verifyCount(builder.delegate, never()) builder:builder createdObjects:anything()];
}
I'm using OCHamcrest and OCMockito. This test passes.
I would avoid trying to simulate thread timing in unit tests and focus more on figuring out what all the possible end states could be regardless of where the timing falls, and write tests for code under those conditions. This avoids endless complexity in your tests, as bbum points out as well.
In your case it seems the condition you need to be testing for is if the call to notifyDelegateCreatedObjects happens after the action is canceled, because the cancel came too late. So instead just unit test the handling of that scenario downstream in your notifyDelegateCreatedObjects method, or whatever class is being notified of that aborted event because of the thread timing.
I know this is not a specific answer to your question but I think its a better approach to achieve the same unit testing goal.
There is no reason to use volatile if your property is atomic and you always go through the setter/getter.
As well, this is a bit of re-inventing the wheel, as noted in the comments.
In general trying to unit test cancellation with any hope of full coverage is very hard because you can't really effectively test all possible timing interactions.

iOS: Stopping a Thread / Method in the Middle of Process

I have a UITextfield and a UIButton. The user can enter, for example, search word such as "dog" or "cat" and it will trigger a method in another class that runs on a custom dispatch GCD queue to fetch the images (around 100 or so).
Everything works fine, except if the user in the midst of fetching, decides to change and enter another search word such as "cat" and then press the fetch button, I would like to be able to stop that thread / method while it is fetching the images from the previous search term.
I have thought about NSThread (something I never used before) or blocks (to get notified once the method has finished running), but the problem with blocks is, I will get notified once the method had finished doing its thing, but what I need here is to tell it to stop fetching (because the user has decided on another search and entered another search term).
Can someone please cite me with some samples, as to how we can be able to stop a loop / method while it is running on a custom GCD thread before it is finished? Thanks in advance.
I'm using NSOperationand NSOperationQueue to cluster markers on a map in the background and to cancel the operation if necessary.
The function to cluster the markers is implemented in a subclass of NSOperation:
ClusterMarker.h:
#class ClusterMarker;
#protocol ClusterMarkerDelegate <NSObject>
- (void)clusterMarkerDidFinish:(ClusterMarker *)clusterMarker;
#end
#interface ClusterMarker : NSOperation
-(id)initWithMarkers:(NSSet *)markerSet delegate:(id<ClusterMarkerDelegate>)delegate;
// the "return value"
#property (nonatomic, strong) NSSet *markerSet;
// use the delegate pattern to inform someone that the operation has finished
#property (nonatomic, weak) id<ClusterMarkerDelegate> delegate;
#end
and ClusterMarker.m:
#implementation ClusterMarker
-(id)initWithMarkers:(NSSet *)markerSet delegate:(id<ClusterMarkerDelegate>)delegate
{
if (self = [super init]) {
self.markerSet = markerSet;
self.delegate = delegate;
}
return self;
}
- (void)main {
#autoreleasepool {
if (self.isCancelled) {
return;
}
// perform some Überalgorithmus that fills self.markerSet (the "return value")
// inform the delegate that you have finished
[(NSObject *)self.delegate performSelectorOnMainThread:#selector(clusterMarkerDidFinish:) withObject:self waitUntilDone:NO];
}
}
#end
You could use your controller to manage the queue,
self.operationQueue = [[NSOperationQueue alloc] init];
self.operationQueue.name = #"Überalgorithmus.TheKillerApp.makemyday.com";
// make sure to have only one algorithm running
self.operationQueue.maxConcurrentOperationCount = 1;
to enqueue operations, kill previous operations and the like,
ClusterMarker *clusterMarkerOperation = [[ClusterMarker alloc] initWithMarkers:self.xmlMarkerSet delegate:self];
// this sets isCancelled in ClusterMarker to true. you might want to check that variable frequently in the algorithm
[self.operationQueue cancelAllOperations];
[self.operationQueue addOperation:clusterMarkerOperation];
and to respond to the callbacks when the operation has finished:
- (void)clusterMarkerDidFinish:(ClusterMarker *)clusterMarker
{
self.clusterMarkerSet = clusterMarker.markerSet;
GMSProjection *projection = [self.mapView projection];
for (MapMarker *m in self.clusterMarkerSet) {
m.coordinate = [projection coordinateForPoint:m.point];
}
// DebugLog(#"now clear map and refreshData: self.clusterMarkerSet.count=%d", self.clusterMarkerSet.count);
[self.mapView clear];
[self refreshDataInGMSMapView:self.mapView];
}
If I remember correctly I used this tutorial on raywenderlich.com as a starter.
I would recommend using NSOperation as it has cancel method which will cancel the current running operation.

block_copy when to use

When to copy a block? The document says, blocks are "deleted when execution returns from the scope in which they are defined.This means you can’t return them directly from a function. If blocks could only be used while their defining scope was still on the call stack, they wouldn’t be nearly as useful as they actually are"
So, here is code which I tried, hoping the block will be deleted once execution is completed in viewDidLoad.
MyReaderController.h
#interface MyReaderController : UIViewController
{
myBlockVar aBlockVar;
}
-(myBlockVar) getABlock;
#end
MyReaderController.m
#implementation MyReaderController
- (void)viewDidLoad
{
[super viewDidLoad];
aBlockVar=[self getABlock];
NSLog(#"Block Result = %f",aBlockVar(1));
}
-(void) viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
NSLog(#"Block Exists even after the execution completes=%# %f",aBlockVar,aBlockVar(5));
}
-(myBlockVar) getABlock{
return ^(int var){return 4.0f;};
}
#end
So, does this code require viewDidLoad to be changed to as coded below, if not then when should I use it.
- (void) viewDidLoad{
[super viewDidLoad];
aBlockVar=Block_copy([self getABlock]);
NSLog(#"Block Result = %f",aBlockVar(1));
}
PART 2
Later on I tried with this following code, hoping now it will return aBlockVar as nil obj in
viewDidDisappear.
- (void)viewDidLoad
{
[super viewDidLoad];
Blocker *blocker=[[Blocker alloc] init];
myBlockVar myVar=[blocker getABlock];
aBlockVar=myVar;
NSLog(#"Block Result = %f",aBlockVar(1));
blocker=nil;
myVar=nil;
}
Blocker.m
#import "Blocker.h"
#implementation Blocker
-(myBlockVar) getABlock{
return ^(int var){return 4.0f;};
}
#end
Are you using ARC? If so, you don't need to use Block_copy or Block_release.
If you are, then you are correct with your revised code, as Block_copy takes it off the stack and into the heap where it is has an effective retain count of 1. You would also need to call Block_release where appropriate, when finally finished with the block, to bring its balance the copy, effectively bringing the retain count back to 0.
use #property (nonatomic, copy) (int)(^myBlock)(void);
let the system do all right memory management for you!
initialize:
self.myBlock = ^int(void){
return 4.0;
};
if you want to destroy your block somewhere do self.myBlock = NULL;
An addendum to the existing answers:
Even if you're using ARC, there are certain situations where you still need Block_copy.
For example, extracting a block argument from an NSInvocation and using it after the function returns.
- (void)interceptInvocation:(NSInvocation *)call {
BlockType block;
[call getArgument:&block atIndex:2]; // ARC cannot see this happen
block = (__bridge BlockType)Block_copy((__bridge void *)block);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
block();
});
}
Without the copy, the block will have been deallocated by the time it is run.
It appears a matching Block_release is not necessary, as when I added one it crashed due to too many releases.
with arc never, without arc:
: when you have a STACK block and want to keep it as a HEAP block (e.g. when you have a block in a function and want it to live after you exited the function!)
You need to block_copy it then.
also you need retain/release it as you would a NSString so (using block_copy/block_release)

Suggestions on making this threadsafe, yet efficient?

I have been thinking about a problem that seemingly would be simple to implement, yet an efficient and threadsafe solution is stymying me. What I want to do is create some sort of worker object. Several callers may ask it to work from different threads. A requirement is that requests must not queue up. In other words if somebody asks the worker to do work but sees it is already doing work, it should just return early.
A simple first pass is this:
#interface Worker : NSObject
#property (nonatomic, assign, getter = isWorking) BOOL working;
- (void)doWork;
#end
#implementation Worker
{
dispatch_queue_t _workerQueue; //... a private serial queue
}
- (void)doWork
{
if ( self.isWorking )
{
return;
}
self.working = YES;
dispatch_async(_workerQueue, ^{
// Do time consuming work here ... Done!
self.working = NO;
});
}
#end
The problem with this is that the isWorking property is not threadsafe. Marking it atomic won't help here, as accesses to it need to be synchronized across a few statements.
To make it threadsafe I would need to protect the isWorking with a lock:
#interface Worker : NSObject
#property (nonatomic, assign, getter = isWorking) BOOL working;
- (void)doWork;
#end
#implementation Worker
{
dispatch_queue_t _workerQueue; //... a private serial queue
NSLock *_lock; // assume this is created
}
- (void)doWork
{
[_lock lock];
if ( self.isWorking )
{
[_lock unlock];
return;
}
self.working = YES;
[_lock unlock];
dispatch_async(_workerQueue, ^{
// Do time consuming work here ... Done!
[_lock lock];
self.working = NO;
[_lock unlock];
});
}
#end
While I do believe this would be threadsafe, I think it's pretty crummy to have to take and give up a lock (an expensive operation) so frequently.
So, is there a more elegant solution?
dispatch_semaphore is the idiomatic way to limit access to a finite resource, if you're already using GCD.
// Add an ivar:
dispatch_semaphore_t _semaphore;
// To initialize:
_semaphore = dispatch_semaphore_create(1);
// To "do work" from any thread:
- (void)doWork
{
if (dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_NOW) == 0) {
// We got the semaphore without waiting, so we're first in line.
dispatch_async(_workerQueue, ^{
// do time consuming work here, then when done:
dispatch_semaphore_signal(_semaphore);
});
} else {
// We would have had to wait for the semaphore, so somebody must have
// been doing work already, and we should do nothing.
}
}
Here's a blog post explaining in more detail.
You may be able to use an atomic test-and-set operation here. GCC provides __atomic_test_and_set for this purpose. Here's how you might use it in C (untested):
static volatile bool working = FALSE;
if(__atomic_test_and_set(&working, __ATOMIC_ACQUIRE)) {
// Already was working.
}else{
// Do work, possibly in another thread.
// When done:
__atomic_clear(&working, __ATOMIC_RELEASE);
}
Easy, huh?
For making a property thread-safe you could simply use #synchronize.

Resources