1

I have to implement some .Net code involving a shared resource accessed by different threads. In principle, this should be solved with a simple read write lock. However, my solution requires that some of the read accessions do end up producing a write operation. I first checked the ReaderWriterLockSlim, but by itself it does not solve the problem, because it requires that I know in advance if a read operation can turn into a write operation, and this is not my case. I finally opted by simply using a ReaderWriterLockSlim, and when the read operation "detects" that needs to do a write operation, release the read lock and acquire a write lock. I am not sure if there is a better solution, or event if this solution could lead to some synchronization issue (I have experience with Java, but I am fairly new to .Net).

Below some sample code illustrating my solution:

public class MyClass
{
    private int[] data;

    private readonly ReaderWriterLockSlim syncLock = new ReaderWriterLockSlim();

    public void modifyData()
    {
        try
        {
            syncLock.EnterWriteLock();

            // clear my array and read from database...
        }
        finally
        {
            syncLock.ExitWriteLock();
        }
    }

    public int readData(int index)
    {
        try
        {
            syncLock.EnterReadLock();
            // some initial preprocessing of the arguments

            try
            {
                _syncLock.ExitReadLock();
                _syncLock.EnterWriteLock();

                // check if a write is needed <--- this operation is fast, and, in most cases, the result will be false
                // if true, perform the write operation
            }
            finally
            {
                _syncLock.ExitWriteLock();
                _syncLock.EnterReadLock();
            }

            return data[index];
        }
        finally
        {
            syncLock.ExitReadLock();
        }
    }

}
Alberto Anguita
  • 103
  • 1
  • 11
  • Why can't you just use two plain objects (one for read and one for write) and "lock" statement? – Matas Apr 16 '18 at 09:17
  • Whether it's a good solution depends on nature of operation you perform in that `readData`. I suppose you realize that both readers and writers can intercept you between `ExitReadLock` and `EnterWriteLock`. If you are fine with that - then it's fine. – Evk Apr 16 '18 at 09:17
  • ReaderWriter Lock Class has: method UpgradeToWriterLock() -- which is for the scenarios like yours. – Prateek Shrivastava Apr 16 '18 at 09:20
  • @Matas Using two separate locks is no solution because that would lead to writes being performed simultaneously with reads. – Alberto Anguita Apr 16 '18 at 09:23
  • @Prateek The UpgradeToWriterLock() approach involves that only one read will be able to access at a time, loosing the advantage of simultaneous reads. Entering in upgradeable mode is only allowed to one thread, as far as I undertand. – Alberto Anguita Apr 16 '18 at 09:26
  • @Evk Yes, I am aware that both reads and writes can stop a thread at that point. It does not break my read ops, so I guess is it fine. – Alberto Anguita Apr 16 '18 at 09:29
  • @AlbertoAnguita - Simulataneous Reads are never a problem for in-memory data right. Moreover - Upgrading to writer lock does not mean that only one thread can Read. It means that now the read thread that requested the writer lock will wait for the write lock to be alloted before it can modify the shared resource. It does not affect other simultaneous reads. – Prateek Shrivastava Apr 16 '18 at 09:32
  • Well if you are sure it's fine (that is - will not lead to inconsistency and\or deadlocks) - then it's fine. Note that if you are implementing some kind of a cache - you might have better luck with something like `ConcurrentDictionary`. – Evk Apr 16 '18 at 09:34
  • Have you looked at [`ReaderWriterLockSlim.EnterUpgradeableReadLock()`](https://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.enterupgradeablereadlock(v=vs.110).aspx) ? – Matthew Watson Apr 16 '18 at 09:37
  • Before you overcomplicate things, try using a simple `lock(readOrWriteLock)` for all actions. That `return data[index];` looks so simple that 'concurrent reads' shouldn't be a noticeable benefit. – H H Apr 16 '18 at 09:38
  • Side note: Your try/finally blocks are structured wrong. Suppose an `EnterLock()` throws? – H H Apr 16 '18 at 09:41
  • @MatthewWatson it will not help OP, because only one thread can enter upgradable read lock, and since OP doesn't know in advance whether he needs upgradable lock or not - he have to enter it every time instead of usual read lock, which basically defeats the whole point of `ReaderWriterLock`. – Evk Apr 16 '18 at 09:41
  • @Prateek - I think I am now understanding the ReadWriteLockSlim properly... I cannot "upgrade" from read mode to upgradeable mode, but I can downgrade from upgradeable mode to read mode. Therefore, I should first enter in upgradeable mode, and after I have done the optionat write part, downgrade to read mode, right? – Alberto Anguita Apr 16 '18 at 09:45
  • @Henk Holterman - the code is just a sample. The read operation is not a simple index lookup, so I am looking for the benefits of shared reading. – Alberto Anguita Apr 16 '18 at 09:47
  • I thought so - but you should still be very sure that it pays. – H H Apr 16 '18 at 09:50
  • Not the answer but consider this. What should happen if two readers have the read lock and want to upgrade it to the write lock at the same time? For one of them to succeed another must actually relinquish its read lock, and repeat the reading before trying to write again. – Dialecticus Apr 16 '18 at 10:15

0 Answers0