Cross-process read-write synchronization primative in .NET?

后端 未结 5 759
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-02-06 08:07

Is there a read/write locking mechanism that works across processes (similar to Mutex, but read/write instead exclusive locking)? I would like to allow concurrent read access,

相关标签:
5条回答
  • 2021-02-06 08:45

    Windows does not include a cross process Reader-Writer lock. A combination of Semaphore and Mutex could be used to construct ones (the Mutex is held by a writer for exclusive access or by a Reader which then uses the Semaphore to release other readers—i.e. writers would wait on just the mutex and readers for either).

    However, if contention is expected to be low (i.e. no thread holds a lock for long) then mutual exclusion may still be faster: the additional complexity of the reader-writer lock overwhelms any benefit of allowing multiple readers in. (A reader-writer lock will only be faster if there are many more readers and locks are held for significant time—but only your profiling can confirm this.)

    0 讨论(0)
  • 2021-02-06 08:56

    No. As Richard noted above, there is no such out of the box mechanism in .NET. This is how to implement it using a mutex and a semaphore.

    Method #1 is described in http://www.joecheng.com/blog/entries/Writinganinter-processRea.html, quoting:

    // create or open global mutex
    GlobalMutex mutex = new GlobalMutex("IdOfProtectedResource.Mutex");
    // create or open global semaphore
    int MoreThanMaxNumberOfReadersEver = 100;
    
    GlobalSemaphore semaphore = new GlobalSemaphore("IdOfProtectedResource.Semaphore", MoreThanMaxNumberOfReadersEver);
    
    public void AcquireReadLock()
    {
      mutex.Acquire();
      semaphore.Acquire();
      mutex.Release();
    }
    
    public void ReleaseReadLock()
    {
      semaphore.Release();
    }
    
    public void AcquireWriteLock()
    {
      mutex.Acquire();
      for (int i = 0; i < MoreThanMaxNumberOfReadersEver; i++)
        semaphore.Acquire(); // drain out all readers-in-progress
      mutex.Release();
    }
    
    public void ReleaseWriteLock()
    {
      for (int i = 0; i < MoreThanMaxNumberOfReadersEver; i++)
        semaphore.Release();
    }
    

    An alternative would be:

    Read locking - as above. Write locking as follows (pseudocode):

    - Lock mutex
    - Busy loop until the samaphore is not taken AT ALL:
    -- wait, release.
    -- Release returns value; 
    -- if value N-1 then break loop.
    -- yield (give up CPU cycle) by using Sleep(1) or alternative
    - Do write
    - Release mutex
    

    It must be noted that more efficient approach is possible, as here: http://en.wikipedia.org/wiki/Readers-writers_problem#The_second_readers-writers_problem Look for the words "This solution is suboptimal" in the article above.

    0 讨论(0)
  • 2021-02-06 08:57

    I've created this class based on Pavel's answer. I haven't tested it extensively yet, but I've created a simple winforms application to test it and so far it works well.

    Please note, that it uses a semaphore, so it doesn't support reentrancy.

    public class CrossProcessReaderWriterLock
    {
        private readonly string _name;
        const int _maxReaders = 10;
    
        readonly Mutex     _mutex;
        readonly Semaphore _semaphore;
    
        public CrossProcessReaderWriterLock(string name)
        {
            _name = name;
            _mutex     = new Mutex(false, name + ".Mutex");
            _semaphore = new Semaphore(_maxReaders, _maxReaders, name + ".Semaphore");
        }
    
        public void AcquireReaderLock()
        {
            //Log.Info($"{_name} acquiring reader lock...");
    
            _mutex    .WaitOne();
            _semaphore.WaitOne();
            _mutex    .ReleaseMutex();
    
            //Log.Info($"{_name} reader lock acquired.");
        }
    
        public void ReleaseReaderLock()
        {
            _semaphore.Release();
    
            //Log.Info($"{_name} reader lock released.");
        }
    
        public void AcquireWriterLock()
        {
            //Log.Info($"{_name} acquiring writer lock...");
    
            _mutex.WaitOne();
    
            for (int i = 0; i < _maxReaders; i++)
                _semaphore.WaitOne(); // drain out all readers-in-progress
    
            _mutex.ReleaseMutex();
    
            //Log.Info($"{_name} writer lock acquired.");
        }
    
        public void ReleaseWriterLock()
        {
            for (int i = 0; i < _maxReaders; i++)
                _semaphore.Release();
    
            //Log.Info($"{_name} writer lock released.");
        }
    }
    
    0 讨论(0)
  • 2021-02-06 08:57

    System.Threading.Mutex has a mutex that can be used for intra-process communication. If you would like functionality that it doesn't support, it can be implemented via a mutex.

    0 讨论(0)
  • 2021-02-06 09:06

    Have you looked at System.Threading.ReaderWriteLock? Here's the MSDN Link.

    0 讨论(0)
提交回复
热议问题