代码之家  ›  专栏  ›  技术社区  ›  Charles

是否存在全局命名的读写器锁?

  •  16
  • Charles  · 技术社区  · 17 年前

    4 回复  |  直到 17 年前
        1
  •  19
  •   Jim Mischel    17 年前

    此锁将允许1个写入器独占访问或N个(可能很大,但您必须定义)读取器并发访问。

    这是它的工作原理。我将以10位读者为例。

    初始化一个最初没有信号的命名互斥体和一个有10个槽位的命名信号量:

      Mutex m = new Mutex(false, "MyMutex");
      Semaphore s = new Semaphore(10, 10, "MySemaphore");
    

    获取读卡器锁:

    // Lock access to the semaphore.
    m.WaitOne();
    // Wait for a semaphore slot.
    s.WaitOne();
    // Release mutex so others can access the semaphore.
    m.ReleaseMutex();
    

    松开读卡器锁:

    s.Release();
    

    // Lock access to the seamphore
    m.WaitOne();
    // Here we're waiting for the semaphore to get full,
    // meaning that there aren't any more readers accessing.
    // The only way to get the count is to call Release.
    // So we wait, then immediately release.
    // Release returns the previous count.
    // Since we know that access to the semaphore is locked
    // (i.e. nobody can get a slot), we know that when count
    // goes to 9 (one less than the total possible), all the readers
    // are done.
    s.WaitOne();
    int count = s.Release();
    while (count != 9)
    {
        // sleep briefly so other processes get a chance.
        // You might want to tweak this value.  Sleep(1) might be okay.
        Thread.Sleep(10);
        s.WaitOne();
        count = s.Release();
    }
    
    // At this point, there are no more readers.
    

    m.ReleaseMutex();
    

    虽然很脆弱(使用此方法的每个进程的信号量计数最好都是相同的!),但我认为只要你不太努力,它就会做你想做的事情。

        2
  •  1
  •   Michael Meadows    17 年前

    Jim Mischel's fine answer ,但我认为通过避免使用Thread可以提高性能。Sleep(),避免多个读取器试图同时获取时的锁争用!

    初始化

      Mutex writer = new Mutex(false, "Global\\MyWriterMutex");
      Semaphore readers = new Semaphore(int.MaxValue, int.MaxValue, "Global\\MyReadersSemaphore");
      EventWaitHandle readAllowed = new EventWaitHandle(true, EventResetMode.ManualReset, "Global\\MyReadAllowedEvent");
      EventWaitHandle readFinished = new EventWaitHandle(false, EventResetMode.ManualReset, "Global\\MyReadFinishedEvent");
    

      while (true)
      {
        // signal that I'm reading 
        readers.WaitOne();
    
        // check whether I'm actually allowed to read
        if (readAllowed.WaitOne(0))
        {
          break; // great!
        }
    
        // oops, nevermind, signal that I'm not reading
        readers.Release();
        readFinished.Set();
    
        // block until it's ok to read
        readAllowed.WaitOne();
      }
    
      try
      {
        readData();
      }
      finally
      {
        // signal that I'm no longer reading
        readers.Release();
        readFinished.Set();
      }
    

      // block until I am the only writer
      try
      {
        writer.WaitOne();
      }
      catch (AbandonedMutexException)
      {
        // The mutex was abandoned in another process, but it was still acquired
      }
    
      // signal that readers need to cease
      readAllowed.Reset();
    
      // loop until there are no readers
      int readerCount = -1;
      while (readerCount != 0)
      {
        // wipe the knowledge that a reader recently finished
        readFinished.Reset();
    
        // check if there is a reader
        readers.WaitOne();
        readerCount = int.MaxValue - (readers.Release() + 1);
        if (readerCount > 0)
        {
          // block until some reader finishes
          readFinished.WaitOne();
        }
      }
    
      try
      {
        writeData();
      }
      finally
      {
        // signal that readers may continue, and I am no longer the writer
        readAllowed.Set();
        writer.ReleaseMutex();
      }
    
        3
  •  1
  •   Matt Brunell    17 年前

    这个怎么样?不要提供文件。提供 文件。当你需要进行更改时,创建一个新文件,并从那时起提供一份副本。

        4
  •  1
  •   Nathan Schubkegel    9 年前

    您可以使用服务来提供文件。这解决了两个问题。首先,正如您所述,并发性问题。此外,即使您可以实现同步,如果您开始负载平衡,它也会变得更加困难和丑陋。使用服务提供文件可能会降低性能,但可以解决同步问题。