How to implement a reentrant locking mechanism in objective-c through GCD? - objective-c

I have an objective-c class with some methods, which use a GCD queue to ensure that concurrent accesses to a resource take place serially (standard way to do this).
Some of these methods need to call other methods of the same class. So the locking mechanism needs to be re-entrant. Is there a standard way to do this?
At first, I had each of these methods use
dispatch_sync(my_queue, ^{
// Critical section
});
to synchronize accesses. As you know, when one of these methods calls another such method, a deadlock happens because the dispatch_sync call stops the current executing until that other block is executed, which can't be executed also, because execution on the queue is stopped. To solve this, I then used e.g. this method:
- (void) executeOnQueueSync:(dispatch_queue_t)queue : (void (^)(void))theBlock {
if (dispatch_get_current_queue() == queue) {
theBlock();
} else {
dispatch_sync(queue, theBlock);
}
}
And in each of my methods, I use
[self executeOnQueueSync:my_queue : ^{
// Critical section
}];
I do not like this solution, because for every block with a different return type, I need to write another method. Moreover, this problem looks very common to me and I think there should exist a nicer, standard solution for this.

First things first: dispatch_get_current_queue() is deprecated. The canonical approach would now be to use dispatch_queue_set_specific. One such example might look like:
typedef dispatch_queue_t dispatch_recursive_queue_t;
static const void * const RecursiveKey = (const void*)&RecursiveKey;
dispatch_recursive_queue_t dispatch_queue_create_recursive_serial(const char * name)
{
dispatch_queue_t queue = dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL);
dispatch_queue_set_specific(queue, RecursiveKey, (__bridge void *)(queue), NULL);
return queue;
}
void dispatch_sync_recursive(dispatch_recursive_queue_t queue, dispatch_block_t block)
{
if (dispatch_get_specific(RecursiveKey) == (__bridge void *)(queue))
block();
else
dispatch_sync(queue, block);
}
This pattern is quite usable, but it's arguably not bulletproof, because you could create nested recursive queues with dispatch_set_target_queue, and trying to enqueue work on the outer queue from inside the inner one would deadlock, even though you are already "inside the lock" (in derision quotes because it only looks like a lock, it's actually something different: a queue — hence the question, right?) for the outer one. (You could get around that by wrapping calls to dispatch_set_target_queue and maintaining your own out-of-band targeting graph, etc., but that's left as an exercise for the reader.)
You go on to say:
I do not like this solution, because for every block with a different
return types, I need to write another method.
The general idea of this "state-protecting serial queue" pattern is that you're protecting private state; why would you "bring your own queue" to this? If it's about multiple objects sharing the state protection, then give them an inherent way to find the queue (i.e., either push it in at init time, or put it somewhere that's mutually accessible to all interested parties). It's not clear how "bringing your own queue" would be useful here.

Related

#synchronized(self) block at multiple places for multiple resources in multithreaded environment , objective c

Does locking in one function from a thread, blocks all other thread trying to acquire the lock in different functions.
We can use gcd for accessing the critical sections mentioned below, just wanted to know how #synchronized(self) works.
For ex.
Do multiple threads with ONLY writeString() calls gets blocked when the execution is in #synchronized(self){ } in writeString()?
OR
all the threads calling the functions of the same class with #synchronized(self){} (e.g.readDataFromFile()) gets blocked when execution is in #synchronized(self){ } in writeString() ?
-(void)writeString:(NSString*)string forObj:(id)obj
{
#synchronized(self)
{
[obj write:string];
}
}
-(void)readDataFromFile:(NSString*)file
{
#synchronized(self)
{
[self read];
}
}
#synchronized(A) can be thought of as a lock where A identifies the lock to use.
If you pass the same value for A into two calls to #synchronized(), then they'll use the same lock and be exclusive. If you pass two different values for two calls, then they will not be exclusive.
So for this one, we need to zoom out to a bit of a larger context.
In the case where you have two instances:
YourClass *a = [[YourClass alloc] init];
YourClass *b = [[YourClass alloc] init];
a will sync access to both methods for itself.
b will sync access to both methods for itself.
So for instance, concurrently from two different threads, a and b can both run -writeString:forObj: at the same time without blocking.
Now if you changed the implementation to use #synchronized(self.class) that entirely changes the game. Rather than syncing on the 'instance', you would be syncing on the 'class' as a whole, so every instance would have to sync access to the methods.
So for instance using the use #synchronized(self.class) implementation, concurrently from two different threads, if a and b both run -writeString:forObj: at the same time, that would then serialize those calls so only one runs while the other is blocked waiting for the sync to unlock.
I hope that clarifies the difference between locking on an instance of a class vs locking every instance for a given class.
Edit:
May also be worth noting, if you use #synchronized(self) in a 'class' method like the following:
// implementation of 'ExampleClass'
+(void)serializeWriting:(NSString*)string toObj:(id)obj {
#synchronized(self) {
[obj write:string];
}
}
That also changes the game, so anytime that method is called, its synced against the class itself, so something like [ExampleClass serializeWriting:#"some string" toObj:somethingElse] would only ever run the critical section [obj write:string] on a single thread no matter how many places/threads it was called from.

Best way to return from a method when inside a synchronously executed block in objective-c?

For synchronizing access to resources, I need to use a certain serial queue when checking for a condition which decides if a method should return or not. The rest of the method does not need to be executed on the serial queue, thus I would like to execute it on the calling queue to make the serial queue available for other tasks as quickly as possible. The below code that I'm currently using works fine, but it does not look elegant. I'm simply looking for more elegant code doing the same thing:
- (void) blockInvokingMethod {
__block BOOL returnConditionResult;
dispatch_sync(someSerialQueue, ^{
returnConditionResult = [self isReturnConditionMet];
if (returnConditionResult) {
return; // this return should return from the blockInvokingMethod
}
[self doOtherStuffRequiringSerialQueue];
});
if (returnConditionResult) { // have to check again and return again if true
return;
}
[self doStuffNotRequiringSerialQueue];
}
I have the feeling that I'm doing something in a too complicated way. Maybe this code already implies that my structure of synchronizing access is already too complicated.

Does #synchronized block a whole thread

Say you do
MyLock *lock = [[MyLock new] autorelease];
#synchronized(lock) {
NSLog(#"Hello World");
//some very long process
}
In the main thread. Does that mean till //some very long process is done, the main thread is locked? If some other thread call
//Update on the main thread
dispatch_sync(dispatch_get_main_queue(), ^{
//Do some updates
});
That some updates will never be called? Am I correct?
If the code in the first code snippet never finishes, the second one won't be called, regardless of the #synchronized statement. The thread is blocked by the code that you're executing. The #synchronized statement is to synchronize data access between multiple threads and to be useful, it requires that all participating threads actually use the statement. It will not "magically" lock access to the data structure, unless all participating threads "agree" on it.
You don't use #synchronized to ensure that only one method executes on a given (single) thread, that is the case anyhow.
To give you a concrete example of its use, let's say you have an NSMutableArray that you want to protect from getting modified from different threads at the same time (which could lead to data corruption). In that case, you could always access it in a #synchronized block with the same lock token.
Example:
//Thread 1:
#synchronized (myArray) {
[myArray addObject:#"foo"];
}
//Thread 2:
#synchronized (myArray) {
[myArray removeObjectAtIndex:0];
}
This will ensure that the blocks of code that are enclosed by the #synchronized will never execute simultaneously. When one thread enters the block, other threads wait until it finishes, but only if they also use the same #synchronized statement. If you forget to use it on one thread, it doesn't help at all if you used it on the other.
The short answer is no. I think you dont understand the concept of locking. You should read more about syncchronization for example here:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html
You have to synchronize using the same locking object (same instance!) in every case when you access the code, which you are trying to protect. You can store the locking object as property of a class.
In your case:
self.lock = [[MyLock new] autorelease]; //in init method initialize retain or strong lock property
...
#synchronized(self.lock) {
NSLog(#"Hello World");
//some very long process
}
//Update on the main thread
dispatch_sync(dispatch_get_main_queue(), ^{
#synchronized(self.lock) {
NSLog(#"Hello World");
//some very long process
}
});
If you can use as the locking object, the object which your are trying to protect.

Objective C send message to creator

I don't quite understand about how to deal with next kind of task:
#implementation SomeInterface
-(void)DoSomething
{
MyObj * mo = [MyObj new];
[mo doJob];
}
end
The question is - how can mo send message back to SomeInterface after doJob is finished?
Should I use NSNotificationCenter?
As of iOS 4, probably the easiest thing to do is to pass a block to doJob that dictates what it should do upon completion. So, for example...
MyObj.h:
// create a typedef for our type of completion handler, to make
// syntax cleaner elsewhere
typedef void (^MyObjDoJobCompletionHandler)(void);
#interface MyObj
- (void)doJobWithCompletionHandler:(MyObjDoJobCompletionHandler)completionHandler;
#end
MyObj.m:
- (void)doJobWithCompletionHandler:(MyObjDoJobCompletionHandler)completionHandler
{
/* do job here ... */
// we're done, so give the completion handler a shout.
// We call it exactly like a C function:
completionHandler();
/* alternatives would have been to let GCD dispatch it,
but that would lead to discussion of GCD and a bunch of
thread safety issues that aren't really relevant */
}
Within SomeInterface.m:
-(void)DoSomething
{
MyObj * mo = [MyObj new];
[mo doJobWithCompletionHandler:
^() // you can omit the brackets if there are no parameters, but
// that's a special case and I don't want to complicate things...
{
NSLog(#"whoop whoop, job was done");
// do a bunch more stuff here
}
];
}
I assume that in reality you're doing something that ends up being asynchronous in DoJob (or else you'd just wait until the method returns); in that case you might want to use GCD's dispatch_async with the result of dispatch_get_main_queue to ensure the completion handler takes place back on the main thread.
Joachim Bengtsson has written a good introductory guide to blocks. As to how they interact with Grand Central Dispatch (and how to use GCD in general), Apple's documentation is good.
yes, you can use NSNotificationCenter or write callback method

How does this recursive synchronized call not deadlock?

I have a set of methods that all synchronize to the class object (can't use self, because multiple instances of this object could be used in multiple threads). Some of those methods call other methods in the class that also synchronize on the class object. Somehow this works and does not cause the deadlock I would expect it to.
I would assume that testA would be blocked from running because testB already has a lock on the class object, but this apparently isn't the case.
Is it something special that #synchronized is doing or is this a feature of the underlying mutex locks?
Example code that works:
- (NSUInteger)testA
{
#synchronized(self.class)
{
NSLog(#"Doing something in A");
}
return 1;
}
- (void)testB
{
#synchronized(self.class)
{
NSLog(#"Doing something in B");
NSLog(#"A returned: %i", [self testA]);
}
}
When calling testB the output is:
Doing something in B
Doing something in A
A returned: 1
Mauricio's comment is correct. From TOCPL:
The Objective-C synchronization feature supports recursive and reentrant code. A thread can use a single semaphore several times in a recursive manner; other threads are blocked from using it until the thread releases all the locks obtained with it; that is, every #synchronized() block is exited normally or through an exception.