Showing posts with label Design Pattern. Show all posts
Showing posts with label Design Pattern. Show all posts

Saturday, September 17, 2011

Lockless Exclusion Accessor Pattern

With all the work I have been doing with blocks and Grand Central Dispatch (GCD), I have developed a useful design pattern for handling mutual exclusion. I haven’t seen any patterns quite like this one, so I’ll claim it as my own.

Mutual exclusion is always a challenge when multithreading any application. GCD makes mutual exclusion substantially easier by using queues instead of locks. Nevertheless, there are still some challenges. When creating shared data I often include a warning in my documentation that it must only be accessed within a certain serial GCD queue. However, other developers that use my code may not read my documentation. Even I forget occasionally that some particular data isn’t thread safe. So, how do we make this easier? This is a situation for what I call the Lockless Exclusion Accessor pattern. I’ll call it LEA for short. (I also thought of calling it a “letter” since it’s closely related to a getter, but that seemed too silly and generic.)

Before going into the details of LEAs, we need to first understand why encapsulation is important. Most object-oriented languages have the ability to make variables private so they can only be directly accessed internal to the class. Limited access is given to the outside through getters and setters. This prevents classes on the outside making arbitrary changes to another classes internal data. To see how to encapsulate @propertys in Objective-C check out my @property article. We will apply the same principles to our shared data.

First, move your shared data into a class extension so it will not be externally visible. Second, you will want to typdef your block type. This keeps your code cleaner and easier to read. For this example, I’m going to use an NSManagedObjectContext as my shared data. So, my block typedef looks like this:

typedef void(^RBMOCBlock)(NSManagedObjectContext * moc);

Next, you need to create an accessor method. Outside classes will only be able to access your shared data through this method. It will look something like this:

- (void)accessMOCAsync:(RBMOCBlock)block {
        dispatch_async(dispatch_get_main_queue(), ^{
                block([self managedObjectContext]);
        });
}

The dispatch_async takes the passed in block and runs it on the main queue. We could (and really should) modify this code to run on a private serial queue instead. We also pass the shared data to the block. This grants the block exclusive access to that data (as long as the dispatch queue is a serial queue). You’ll also notice that this is an asynchronous call. If needed, we can also make a synchronous LEA. It looks nearly identical:

- (void)accessMOCSync:(RBMOCBlock)block {
        dispatch_sync(dispatch_get_main_queue(), ^{
                block([self managedObjectContext]);
        });
}

Now that we’ve built our asynchronous and synchronous LEAs, let’s use one.

[object accessMOCAsync:^(NSManagedObjectContext * context) {
        // Critical code goes here.
}];

That’s all there is to it. Just wrap your critical code in a block and you get exclusive, local access to the NSManagedObjectContext. LEAs are perfect for Core Data MOCs since they are not thread safe and are often the cause of much grief.

LEAs are also quite flexible. For example, you can merge multiple LEAs into one like this:

[object accessMOCAsync:^(NSManagedObjectContext * context, NSDictionary * userInfo) {
        // Critical code goes here.
}];

The above LEA gives the block exclusive access to two shared variables at once. You can extend this as far as you want. This way to don’t need to write multiple LEAs per class and you don’t need to nest LEAs. However, this comes with a tradeoff. You gain convenience at the cost of more contention for shared data.

Now, LEAs don’t perfectly protect shared data. It’s as good as Objective-C can get though. Rogue developers could pass the pointer to the MOC out of the block. They could also use the dynamic runtime to call the internal getters and setters. However, any developer doing either of these things is asking for a lot of trouble and should not be permitted to write Objective-C code.

For more GCD and block design patterns, check out these sources.


UPDATE:

I've removed all references to SyncSafe due to problems I've discovered.

Saturday, July 30, 2011

One singleton to rule them all

One of the most common design patterns is the singleton. However, implementing singletons, especially in Objective-C, can be very repetitive. I often forget how to properly override all the memory management methods and need to look up a previous singleton. One of the goals of programming is to automate the repetetive, mundane tasks. Cocoa With Love has a great synthesized singleton made from a C pre-processor macro. The problem with this is that it's not flexible. So, I made an Objective-C singleton that can be dropped in any project. By subclassing RBSingleton you can gain all the benefits of a singleton without adding any further code and you have full flexibility to customize each subclass.

There are two main parts that make RBSingleton possible. First, it stores all the singleton instances in a class-wide dictionary. A singleton typically keeps a static pointer to the singleton instance. This works fine as long as it's not subclassed. When subclasses become involved, the subclass that allocates first defines the singleton instance for all subclasses. This restriction is normally beneficial to singletons, but breaks with subclassing. I could have required subclasses to provide a pointer to a static class pointer through a method call, but this imposes more on the subclass's implementation than I wanted. By using a class-wide dictionary, every subclass can store its singleton instance under a unique key. To guarantee a unique key, I simply use the subclass's name.

Second, the singleton instance is allocated by dynamically calling NSObject's -allocWithZone: method as shown below.

Method allocMethod = class_getClassMethod([NSObject class], @selector(allocWithZone:));
sharedInstance = [
method_invoke(self, allocMethod, nil) initialize];

The trick here was to allocate the singleton as the class of the RBSingleton subclass but use NSObject's -allocWithZone: method to do so. This is similar to calling [super allocWIthZone:nil];. The difference is that it's jumping more than one level in the inheritance hierarchy. This is known as a grandsuper call. The Objective-C dynamic runtime makes it possible to make such a call. You will also notice that I hardcoded [NSObject class] into the code. I could have dynamically discovered the root class with the following code:

+ (Class)rootClass {

        
Class rootClass = nil;
        
Class currentClass = [self class];

        
while ((currentClass = class_getSuperclass(currentClass)))
                rootClass = currentClass;

        
return rootClass;
}


If I instead needed to get a grandsuper class that isn't necessarily the root class and I know a subclass of the grandsuper I could use simpler code like this:

[RBSingleton superclass];

Since I know the specific grandsuper class I need, I hardcoded it for efficiency. If you use RBSingleton and find a need to dynamically discover a particular grandsuper class, you can use the above code to do so. I've uploaded RBSingleton as a Gist and you can find it here.

One last note, to use RBSingleton you need to include libobjc.dylib for the dynamic runtime calls.