Example #1
0
    // Acquire the lock for read (shared) access
    public void LockRead()
    {
        lock (monitor) {
            // if there isn’t blocked writers and the resource isn’t being written, grant
            // read access immediately
            if (writeReqQueue.Count == 0 && state >= 0)
            {
                state++;        // add one reader
                return;
            }

            // otherwise, enqueue a read access request

            LockReadRequest request = EnqueueReader();
            // wait until request is granted, or the thread gives up due to interruption
            do
            {
                try {
                    MonitorEx.Wait(monitor, monitor);                           // eq a Monitor.Wait(monitor);
                } catch (ThreadInterruptedException) {
                    // if the requested shared access was granted, we must re-assert interrupt
                    // exception, and return normally.
                    if (request.done)
                    {
                        Thread.CurrentThread.Interrupt();
                        break;
                    }
                    // otherwise, we remove the request from the queue and re-throw the exception
                    RemoveReader();
                    throw;
                }
                // if shared access was granted then return; otherwise, re-wait
            } while (!request.done);
        }
    }
Example #2
0
 private void SyncUnlink(DListNode waiter)
 {
     lock (_lock)
     {
         DListNode.RemoveIfInserted(waiter);
         MonitorEx.PulseAll(_lock, waiter);
     }
 }
Example #3
0
    // acquires the specified number of permits; returns false if times out
    public bool Acquire(int acquires, int timeout = Timeout.Infinite)
    {
        lock (monitor) {
            if (reqQueue.Count == 0 && CanAcquire(acquires))
            {
                AcquireSideEffect(acquires);
                return(true);
            }
            Request request = new Request(acquires);
            reqQueue.AddLast(request);  // enqueue "request" at the end of  "reqQueue"
            TimeoutHolder th = new TimeoutHolder(timeout);
            do
            {
                if ((timeout = th.Value) <= 0)
                {
                    reqQueue.Remove(request);

                    // after remove the request of the current thread from queue, *it is possible*
                    // that the current synhcronization state allows now to satisfy other queued
                    // acquire(s).
                    if (CurrentSynchStateAllowsAcquire())
                    {
                        PerformPossibleAcquires();
                    }

                    return(false);
                }
                try {
                    MonitorEx.Wait(monitor, request, timeout);  // *wait on a private condition variable*
                } catch (ThreadInterruptedException) {
                    // if the acquire operation was already done, re-assert interrupt
                    // and return normally; else remove request from queue and throw
                    // ThreadInterruptedException.
                    if (request.done)
                    {
                        Thread.CurrentThread.Interrupt();
                        return(true);
                    }
                    reqQueue.Remove(request);

                    // after remove the request of the current thread from queue, *it is possible*
                    // that the current synhcronization state allows now to satisfy other queued
                    // acquire(s).
                    if (CurrentSynchStateAllowsAcquire())
                    {
                        PerformPossibleAcquires();
                    }

                    throw;      // ThreadInterruptedException
                }
            } while (!request.done);
            // the request was completed
            return(true);
        }
    }
Example #4
0
 // auxiliary method: grant access to the first waiting writer
 private void GrantAccessToAWaitingWriter()
 {
     if (writeReqQueue.Count > 0)
     {
         LinkedListNode <bool> reqNode = writeReqQueue.First;
         reqNode.Value = true;              // set request.done to true
         state         = -1;                // exclusive lock was taken
         writeReqQueue.RemoveFirst();
         MonitorEx.Pulse(monitor, reqNode); // notify the waiting writer
     }
 }
Example #5
0
 private void GrantAccessToOneWritter()
 {
     if (waitingWriters.Count > 0)
     {
         LinkedListNode <bool> writer = waitingWriters.First; // get first waiting writer
         waitingWriters.RemoveFirst();                        // remove the writer from the wait queue
         writing      = true;                                 // set exclusive lock as taken
         writer.Value = true;                                 // mark exclusive lock request as granted;
         MonitorEx.PulseAll(myLock, writer);                  // notify the specific writer
     }
 }
Example #6
0
 // auxiliary method: grant access to all waiting readers
 private bool GrantAccessToWaitingReaders()
 {
     if (WaitingReaders() > 0)
     {
         readReqQueue.done = true;             // mark all lock read requests as done
         state            += WaitingReaders(); // account with all new active readers
         ClearReaderQueue();
         MonitorEx.PulseAll(monitor, monitor); // notify waiting readers
         return(true);
     }
     return(false);
 }
Example #7
0
 /* 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();
     }
 }
Example #8
0
 // send a message to the queue
 public void Send(T sentMsg)
 {
     lock (monitor) {
         UpdateStateOnSend(sentMsg);
         if (reqQueue.Count > 0)
         {
             Request request = reqQueue.First.Value;
             reqQueue.RemovestFirst();
             request.receivedMsg = ReceiveSideEffect();
             request.done        = true;
             // notify waiting thread on its private condition variable
             MonitorEx.Pulse(monitor, request);
         }
     }
 }
Example #9
0
 // perform the possible pending acquires
 private void PerformPossibleAcquires()
 {
     while (reqQueue.Count > 0)
     {
         Request request = reqQueue.First.Value;
         if (!CanAcquire(request.acquires))
         {
             break;
         }
         // remove request from queue and satisfy it
         reqQueue.RemoveFirst();
         AcquireSideEffect(request.acquires);
         request.done = true;
         MonitorEx.Pulse(monitor, request);      // *specific thread notification*
     }
 }
Example #10
0
 // 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);
     }
 }
Example #11
0
 // send a message to the queue (optimized)
 public void SendOptimized(T sentMsg)
 {
     lock (monitor) {
         if (reqQueue.Count > 0)
         {
             // deliver the message directly to a blocked thread
             Request request = reqQueue.First.Value;
             reqQueue.Remove(request);
             request.receivedMsg = sentMsg;
             request.done        = true;
             // notify waiting thread on its private conditions variable
             MonitorEx.Pulse(monitor, request);
         }
         else
         {
             // no receiving thread, so the message is left in the respective queue
             UpdateStateDueToSend(sentMsg);
         }
     }
 }
Example #12
0
 // receive the next message from the queue
 public bool Receive(out T receivedMsg, int timeout = Timeout.Infinite)
 {
     lock (monitor) {
         if (reqQueue.Count == 0 && CanReceive())
         {
             receivedMsg = ReceiveSideEffect();
             return(true);
         }
         // add a request to the end of the reqQueue
         Request request = new Request();
         reqQueue.AddLast(request);
         TimeoutHolder th = new TimeoutHolder(timeout);
         do
         {
             if ((timeout = th.Value) == 0)
             {
                 // the specified time limit has expired.
                 // Here we know that our request was not satisfied.
                 reqQueue.Remove(request);
                 receivedMsg = default(T);
                 return false,
             }
             try {
                 MonitorEx.Wait(monitor, request, timeout);                      //block on private condition variable
             } catch (ThreadInterruptedException) {
                 // if the acquire operation was already done, re-assert interrupt
                 // and return normally; else remove request from queue and throw
                 // ThreadInterruptedException.
                 if (request.done)
                 {
                     Thread.CurrentThread.Interrupt();
                     break;
                 }
                 reqQueue.Remove(request);
                 throw;
             }
         } while (!request.done);
         receivedMsg = request.receivedMsg;
         return(true);
     }
 }
Example #13
0
        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);
            }
        }
Example #14
0
    // Acquire the lock for write (exclusive) access
    public void LockWrite()
    {
        lock (monitor) {
            // if the lock isn’t held for read nor for writing, grant the access immediately
            if (state == 0)
            {
                state = -1;                     // set state indicating exclusive lock held
                return;
            }
            // enqueue a request for exclusive access
            LinkedListNode <bool> requestNode = writeReqQueue.AddLast(false);
            // wait until request is granted, or the thread gives up due to interruption
            do
            {
                try {
                    MonitorEx.Wait(monitor, requestNode);
                } catch (ThreadInterruptedException) {
                    // if exclusive access was granted, then we re-assert exception, and return normally
                    if (requestNode.Value)
                    {
                        Thread.CurrentThread.Interrupt();
                        break;
                    }
                    // othwewise, remove the request from the queue, and return throwing the exception.
                    writeReqQueue.Remove(requestNode);

                    // when a waiting writer gives up, we must grant shared access to all
                    // waiting readers that has been blocked by this waiting writer
                    if (writeReqQueue.Count == 0 && WaitingReaders() > 0 && state >= 0)
                    {
                        GrantAccessToWaitingReaders();
                    }
                    throw;
                }
                // if the request was granted return, else re-wait
            } while (!requestNode.Value);
        }
    }
Example #15
0
        //---------------------------------------------------------------------
        // Synchronous
        //--
        public bool WaitEx(int timeout, CancellationToken ctk)
        {
            bool          interrupted   = false;
            Waiter <Data> waiter        = null;
            bool          ownsTheWaiter = false;

            lock (_lock)
            {
                if (currentPermits > 0)
                {
                    currentPermits -= 1;
                    return(true);
                }
                // if the current thread must block, check immediate cancelers
                if (timeout == 0)
                {
                    return(false);
                }
                ctk.ThrowIfCancellationRequested();

                // create a synchronous waiter node and insert it in the wait queue
                waiter = new SyncWaiter <Data>(new Data(), ctk, SyncUnlink);
                DListNode.AddLast(waiters, waiter);
                waiter.Enable();

                // wrap timeout value with timeout holder, in order to support timeout adjust
                TimeoutHolder th = new TimeoutHolder(timeout);

                // wait until the request is staisfied, timeout expires or cancellation
                do
                {
                    try
                    {
                        if ((timeout = th.Value) == 0)
                        {
                            ownsTheWaiter = TrySetStateAndRemoveWaiter(waiter, WaiterState.TIMED_OUT);
                            break;
                        }
                        // wait on the monitor's condition variable
                        MonitorEx.Wait(_lock, waiter, timeout);
                    }
                    catch (ThreadInterruptedException)
                    {
                        interrupted   = true;
                        ownsTheWaiter = TrySetStateAndRemoveWaiter(waiter, WaiterState.INTERRUPTED);
                        break;
                    }
                } while (waiter.State == WaiterState.WAITING);
            }

            // this processing is private of the current thread, so we can do it without
            // owning the lock.
            if (ownsTheWaiter)
            {
                waiter.CancelCancellation();
            }
            if (waiter.State == WaiterState.INTERRUPTED)
            {
                throw new ThreadInterruptedException();
            }
            if (interrupted)
            {
                Thread.CurrentThread.Interrupt();
            }
            if (waiter.State == WaiterState.CANCELED)
            {
                throw new OperationCanceledException(ctk);
            }
            return(waiter.State == WaiterState.SUCCESS);
        }
Example #16
0
    // generic acquire operation; returns false when it times out
    public bool Acquire(AcquireArgs acquireArgs, out AcquireResult result, int timeout = Timeout.Infinite)
    {
        lock (monitor) {
            if (reqQueue.Count == 0 && CanAcquire(acquireArgs))
            {
                result = AcquireSideEffect(acquireArgs);
                return(true);
            }
            Request request = new Request(acquireArgs);
            reqQueue.AddLast(request);  // enqueue "request" at the end of the request queue
            TimeoutHolder th = new TimeoutHolder(timeout);
            do
            {
                if ((timeout = th.Value) == 0)
                {
                    // the timeout limit has expired - here we are sure that the acquire resquest
                    // is still pending. So, we remove the request from the queue and return failure.
                    reqQueue.Remove(request);

                    // After remove the request of the current thread from queue, *it is possible*
                    // that the current synhcronization state allows now to satisfy other queued
                    // acquire(s).
                    if (CurrentSynchStateAllowsAquire())
                    {
                        PerformPossibleAcquires();
                    }

                    result = default(AcquireResult);
                    return(false);
                }
                try {
                    MonitorEx.Wait(monitor, request, timeout);  // *wait on a private condition var*
                } catch (ThreadInterruptedException) {
                    // the thread may be interrupted when the requested acquire operation
                    // is already performed, in which case you can no longer give up
                    if (request.done)
                    {
                        // re-assert the interrupt and return normally, indicating to the
                        // caller that the operation was successfully completed
                        Thread.CurrentThread.Interrupt();
                        break;
                    }
                    // remove the request from the queue and throw ThreadInterruptedException
                    reqQueue.Remove(request);

                    // After remove the request of the current thread from queue, *it is possible*
                    // that the current synhcronization state allows now to satisfy other queued
                    // acquire(s).
                    if (CurrentSynchStateAllowsAquire())
                    {
                        PerformPossibleAcquires();
                    }

                    throw;      // ThreadInterruptedException
                }
            } while (!request.done);
            // the request acquire operation completed successfully
            result = request.acquireResult;
            return(true);
        }
    }