Aquí podría ser tu PUBLICIDAD


¿Hay un bloqueo de lector / escritor nombrado global?

votos
14

Tengo varias aplicaciones web asp.net que sirven un conjunto de archivos. Periódicamente, uno actualizará el archivo antes de servirlo, pero no puede actualizar el archivo si está en uso.

Podría resolver este problema usando un mutex con nombre donde el nombre es la ruta del archivo (reemplazando los caracteres no válidos por supuesto). Lo he usado en otras situaciones, pero se puede ver lo ineficiente que es. Solo un proceso podrá servir el archivo a la vez.

Un bloqueo de lector / escritor sería perfecto, pero están diseñados para funcionar en un único proceso. Además, tendría que crear un bloqueo de lector / escritor para cada archivo que pudiera actualizarse, y hay muchos.

Lo que realmente necesito es un bloqueo de lector / escritor que se pueda nombrar como un mutex. ¿Hay tal cosa? ¿O puede crearse tal cosa utilizando los bloqueos existentes?

Publicado el 12/03/2009 a las 20:21
fuente por usuario Charles
En otros idiomas...        العربية       

5 respuestas

votos
17

Es posible simular un bloqueo de lector / escritor utilizando un Mutex y un semáforo. No lo haría si tuviera que acceder a él miles de veces por segundo, pero para docenas o tal vez cientos de veces por segundo, debería funcionar bien.

Este bloqueo permitiría el acceso exclusivo de 1 escritor o el acceso simultáneo de N lectores (posiblemente grandes, pero usted debe definirlo).

Así es como funciona. Usaré 10 lectores como ejemplo.

Inicialice un Mutex con nombre, inicialmente sin nombre, y un semáforo con nombre con 10 ranuras:

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

Adquirir bloqueo del lector:

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

Liberar el bloqueo del lector:

s.Release();

Adquirir bloqueo de escritor:

// 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.

Liberar bloqueo del escritor:

m.ReleaseMutex();

Aunque es frágil (¡cada proceso que usa esto mejor tiene el mismo número para el conteo de semáforos!), Creo que hará lo que quiera siempre y cuando no intente pegarle demasiado.

Respondida el 12/03/2009 a las 09:33
fuente por usuario Jim Mischel


Aquí podría ser tu PUBLICIDAD


votos
3

Un poco tarde, pero me escribió bloquear un lector / escritor llamado hace un rato - http://unintelligible.org/blog/2009/10/20/named-reader-writer-lock-in-c/ . Esto funciona mediante el mantenimiento de una asignación de nombres / bloqueo de ReaderWriterLockSlims, y rodeando el acceso a ese mapa en un monitor.

Respondida el 10/01/2011 a las 02:25
fuente por usuario zcrar70

votos
1

¿Qué tal esto? No sirva archivos. Sirve copias de archivos. Cuando necesite realizar un cambio, cree un nuevo archivo y entregue una copia de eso a partir de ese momento.

Respondida el 12/03/2009 a las 10:36
fuente por usuario Matt Brunell

votos
1

No creo que haya nada que satisfaga sus necesidades según lo establecido (aunque me reservo el derecho de estar equivocado).

Puede servir el archivo usando un servicio. Esto resuelve dos problemas. Primero, como dijiste, el problema de la concurrencia. Además, incluso si puede lograr la sincronización, se vuelve más difícil y feo si inicia el equilibrio de carga. Servir el archivo usando un servicio probablemente le cueste en rendimiento, pero resuelve su problema de sincronización.

Respondida el 12/03/2009 a las 08:33
fuente por usuario Michael Meadows

votos
0

Aprecio bien la respuesta de Jim Mischel , pero veo oportunidad para mejorar el rendimiento al evitar Thread.Sleep () y evitar la contención de bloqueo cuando varios lectores tratar de adquirir al mismo tiempo!

inicialización

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

Lector

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

Escritor

  // 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();
  }
Respondida el 17/08/2017 a las 07:35
fuente por usuario Nathan Schubkegel