/* apenas pode ser invocado pelas threads que tenham * adquirido o semáforo para escrita, liberta o acesso para * escrita e, atomicamente, adquire acesso para leitura.*/ public void DowngradeWriter() { if (waitingReaders != null && waitingReaders.waiters > 0) { readers += waitingReaders.waiters; waitingReaders.done = true; // dar acesso aos leitores waitingReaders = null; // retirar os leitores de espera MonitorEx.PulseAll(myLock, myLock); // notificar todos os leitores } else { GrantAccessToOneWritter(); } }
// DownWrite adquirem a posse do semáforo para escrita public void DownWrite() { lock (myLock) { // nao existem leitores em espera e neinguem está a escrever e a fila de escritores está vazia, // o escritor tem acesso ao semáforo if (readers == 0 && !writing && waitingWriters.Count == 0) { writing = true; return; } // o escritor fica em espera LinkedListNode <bool> wrnode = waitingWriters.AddLast(false); do { try { MonitorEx.Wait(myLock, wrnode); } catch (ThreadInterruptedException) { // acesso foi garantido, o escritor retira-se if (wrnode.Value) { Thread.CurrentThread.Interrupt(); return; } // o escritor é removido da espera waitingWriters.Remove(wrnode); // garantir o acesso dos leitores ao semáforo if (!writing && waitingWriters.Count == 0 && waitingReaders != null) { if (waitingReaders != null && waitingReaders.waiters > 0) { readers += waitingReaders.waiters; waitingReaders.done = true; // dar acesso aos leitores waitingReaders = null; // retirar os leitores de espera MonitorEx.PulseAll(myLock, myLock); // notificar todos os leitores } } throw; } } while (!wrnode.Value); } }
private readonly LinkedList <bool> waitingWriters = new LinkedList <bool>(); // escritores em espera (entra um de cada vez no semáforo) // DownRead adquirem a posse do semáforo para leitura public void DownRead() { lock (myLock) { // não existem escritores à espera e não há nenhum esritor a escrever, // o leitor ganha acesso independentemente dos outros leitores if (waitingWriters.Count == 0 && !writing) { readers++; return; } // o leitor fica em espera WaitingReaders rdnode; if ((rdnode = waitingReaders) == null) { waitingReaders = rdnode = new WaitingReaders(); } rdnode.waiters++; do { try { MonitorEx.Wait(myLock, myLock); } catch (ThreadInterruptedException) { // acesso foi garantido, o leitor retira-se if (rdnode.done) { Thread.CurrentThread.Interrupt(); return; } // o leitor é removido da espera if (--rdnode.waiters == 0) { waitingReaders = null; } throw; } } while (!rdnode.done); } }