Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Re-entrant read/write locking construct?

I'm an experienced .NET programmer and stretching my legs with iOS. One of my favorite multi-threading constructs in .NET is the ReaderWriterLock. It allows for multiple readers or a single writer. The one feature that I am really missing in iOS is that the locks are re-entrant. That is, reader threads can acquire the read lock multiple times as long as they release it the same number of times. Likewise, the single writer thread can acquire the lock multiple times as long as it releases the lock by an equivalent number.

I've looked into the iOS Framework and none of the constructs appear to offer the same support including the re-entrancy. I also looked into the pthread library. I found rwlock, but it does not allow re-entrancy.

Is there anything on iOS that allows for re-entrant read-write locks?

like image 284
Askable Avatar asked Oct 07 '12 02:10

Askable


People also ask

What is read/write lock What is reentrant lock?

The ReadWriteLock is a pair of associated locks, one for read-only operations and one for writing. Whereas, the ReentrantLock is a re-entrant mutual exclusion Lock with the same behavior as the implicit monitor lock accessed using synchronized methods and statements, but with some more extended capabilities.

Which one is re entrant lock type?

As per Javadoc, ReentrantLock is a mutual exclusive lock, similar to implicit locking provided by synchronized keyword in Java, with extended features like fairness, which can be used to provide lock to longest waiting thread.

What is the difference between lock and ReentrantLock?

Lock is an interface. It defines a set of methods that all locks should have. ReentrantLock is a concrete class that implements the Lock interface.

Why do we need read lock?

A reader/writer lock pair allows any number of readers to "own" the read lock at the same time, OR it allows one writer to own the write lock, but it never allows a reader and a writer at the same time, and it never allows more than one writer at the same time.

Why read lock is not allowed when using reentrant read write lock?

If any thread is using the write lock of Reentrant Read Write Lock pair, read lock on resource is not allowed. We use write lock from Reentrant Read Write Lock pair with write code. Acquiring the lock before, then calling the write task in try block and releasing the write lock in finally block.

What is a reentrant Lock?

A reentrant lock is one where a process can claim the lock multiple times without blocking on itself. It's useful in situations where it's not easy to keep track of whether you've already grabbed a lock. If a lock is non re-entrant you could grab the lock, then block when you go to grab it again, effectively deadlocking your own process.

What is the use of read lock in threading?

Read lock allows multiple thread to acquire lock in read method when all the synchronizing threads are using only the read lock of the Reentrant Read Write Lock pair. If any thread is using the write lock of Reentrant Read Write Lock pair, read lock on resource is not allowed.

How do I get the read lock of a read task?

Acquiring the lock before, then calling the read task in try block and releasing the read lock in finally block. Read lock allows multiple thread to acquire lock in read method when all the synchronizing threads are using only the read lock of the Reentrant Read Write Lock pair.


1 Answers

Yes, the @synchronized directive is reentrant. See Using the @synchronized Directive in the Threading Programming Guide and also Threading in the ObjC Programming Language.

That said, you should almost never use this in iOS. In most cases you can avoid locks of all kinds, let alone very heavyweight (slow) locks like reentrant locks. See the Concurrency Programming Guide, and particularly the section Migrating Away from Threads, for extensive information the queue-based approaches that iOS favors over manual thread management and locking.

For example, the reader/writer lock works like this using Grand Central Dispatch:

- (id)init {
   ...
   _someObjectQueue = dispatch_queue_create("com.myapp.someObject", 
                                            DISPATCH_QUEUE_CONCURRENT);
 }

// In iOS 5 you need to release disptach_release(_someObjectQueue) in dealloc,
// but not in iOS 6.

- (id)someObject {
  __block id result;
  dispatch_sync(self.someObjectQueue, ^{
    result = _someObject;
  });
  return result;
}

- (void)setSomeObject:(id)newValue {
  dispatch_barrier_async(self.queue, ^{
    _someObject = newValue;
});

This approach allows unlimited parallel readers, with exclusive writers, while ensuring that writers never starve and that writes and reads are serialized, all while avoiding any kernel calls unless there is actual contention. That's all to say it's very fast and simple.

When a reader comes along, you queue a request to read the value, and wait for it to process. When a writer comes along, it queues a barrier request to update it, which requires that no other requests from that queue are currently running. With this construct, the developer doesn't need to manage any locks. Just put things on the queue in the order you want them to run.

like image 184
Rob Napier Avatar answered Oct 10 '22 12:10

Rob Napier