English 中文(简体)
有全局命名的读/写锁吗?
原标题:
  • 时间:2009-03-12 19:21:23
  •  标签:

我有多个ASP.NET Web应用程序为一组文件提供服务。定期,其中一个会在提供服务之前更新文件,但如果文件正在使用中,则无法更新文件。

我可以通过使用命名互斥锁来解决这个问题,其中名称是文件路径(当然替换无效字符)。我在其他情况下使用过这个,但您可以看到它是多么低效。一次只能有一个进程能够为文件提供服务。

一个读写锁会非常完美,但它们设计用于单一进程内部工作。而且我必须为每个可能被更新的文件创建一个读写锁,而这样的文件有很多。

我真正需要的是一个可以像互斥锁一样命名的读写锁。有这样的东西吗?或者可以使用现有的锁创建这样的东西吗?

最佳回答

可以使用互斥锁和信号量模拟读者/写者锁。如果每秒需要访问数千次,我不会这样做,但是每秒数十次或数百次,它应该可以正常工作。

这个锁将允许一个作者的独占访问,或者允许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();

尽管它很脆弱(每个使用该信号量计数的过程都应该相同!),但我认为只要你不试图过度使用它,它就会做你想要的。

问题回答

我很欣赏Jim Mischel所提供的出色答案,但我认为可以通过避免Thread.Sleep()和避免当多个读取器尝试同时获取时出现锁争用来提高性能!

Initialization

  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");

Reader

  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();
  }

Writer

  // 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();
  }

这个怎么样?不要提供文件。提供文件的副本。当你需要做出改变时,创建一个新文件,然后从此起始提供该副本。

我认为没有任何东西能够满足您所述的需求(尽管我保留错误的权利)。

您可以使用服务来提供该文件。这解决了两个问题。第一个问题,正如您所说,是并发问题。即使您可以实现同步,如果开始负载平衡,它也变得更加困难和麻烦。使用服务来提供该文件可能会损失您的性能,但解决了您的同步问题。





相关问题
热门标签