/// <summary> /// Call this method after accessing the resource to notify the SyncGate that it can grant access to other code. /// </summary> /// <param name="result">The IAsyncResult object given to the callback method when access was granted.</param> public void EndRegion(IAsyncResult result) { ChoGuard.ArgumentNotNull(result, "result"); SyncGateAsyncResult sgar = (SyncGateAsyncResult)result; sgar.EndInvoke(); lock (_syncLock) { if ((sgar.Mode != SyncGateMode.Shared) || (--this._numReaders <= 0)) { if (_qWriteRequests.Count > 0) { _state = SyncGateStates.OwnedByWriter; QueueCallback(_qWriteRequests.Dequeue()); } else if (_qReadRequests.Count > 0) { _state = SyncGateStates.OwnedByReaders; _numReaders = _qReadRequests.Count; while (_qReadRequests.Count > 0) { QueueCallback(_qReadRequests.Dequeue()); } } else { _state = SyncGateStates.Free; } } } }
/// <summary> /// Call this method after accessing the resource to notify the SyncGate that it can grant access to other code. /// </summary> /// <param name="result">The IAsyncResult object given to the callback method when access was granted.</param> public void EndRegion(IAsyncResult result) { if (result == null) { throw new ArgumentNullException("result"); } SyncGateAsyncResult sgar = (SyncGateAsyncResult)result; sgar.EndInvoke(); Monitor.Enter(m_syncLock); if (sgar.Mode == SyncGateMode.Shared) { // Subtract a reader and return (without changing the gate's state) // if this is not the last reader if (--m_numReaders > 0) { Monitor.Exit(m_syncLock); return; } // This was the last reader, wake up any queued requests } Contract.Assume(m_qReadRequests != null); Contract.Assume(m_qWriteRequests != null); // Wake-up any queued requests if (m_qWriteRequests.Count > 0) { // A writer is queued, invoke it m_state = SyncGateStates.OwnedByWriter; QueueCallback(m_qWriteRequests.Dequeue()); } else if (m_qReadRequests.Count > 0) { // Reading requests are queued, invoke all of them m_state = SyncGateStates.OwnedByReaders; m_numReaders = m_qReadRequests.Count; while (m_qReadRequests.Count > 0) { // The 1st reader can run on this thread; the others will be on thread pool threads QueueCallback(m_qReadRequests.Dequeue()); } } else { // No requests are queued, free the gate m_state = SyncGateStates.Free; } Monitor.Exit(m_syncLock); }
/// <summary> /// Allows the caller to notify the SyncGate that it wants exclusive or shared access to a resource. /// </summary> /// <param name="mode">Indicates if exclusive or shared access is desired.</param> /// <param name="asyncCallback">The callback method to invoke once access can be granted.</param> /// <param name="asyncState">Additional state to pass to the callback method.</param> public void BeginRegion(SyncGateMode mode, ChoAsyncCallback asyncCallback, object asyncState) { ChoGuard.ArgumentNotNull(asyncCallback, "asyncCallback"); SyncGateAsyncResult ar = new SyncGateAsyncResult(mode, asyncCallback, asyncState); lock (_syncLock) { switch (mode) { case SyncGateMode.Exclusive: switch (_state) { case SyncGateStates.OwnedByReaders: case SyncGateStates.OwnedByReadersAndWriterPending: _state = SyncGateStates.OwnedByReadersAndWriterPending; _qWriteRequests.Enqueue(ar); break; case SyncGateStates.OwnedByWriter: _qWriteRequests.Enqueue(ar); break; } break; case SyncGateMode.Shared: switch (_state) { case SyncGateStates.Free: case SyncGateStates.OwnedByReaders: _state = SyncGateStates.OwnedByReaders; _numReaders++; QueueCallback(ar); break; case SyncGateStates.OwnedByReadersAndWriterPending: case SyncGateStates.OwnedByWriter: case SyncGateStates.ReservedForWriter: _qReadRequests.Enqueue(ar); break; } break; } } }
/// <summary> /// Allows the caller to notify the SyncGate that it wants exclusive or shared access to a resource. /// </summary> /// <param name="mode">Indicates if exclusive or shared access is desired.</param> /// <param name="asyncCallback">The callback method to invoke once access can be granted.</param> /// <param name="asyncState">Additional state to pass to the callback method.</param> public void BeginRegion(SyncGateMode mode, AsyncCallback asyncCallback, Object asyncState) { Contract.Assume(m_qReadRequests != null); Contract.Assume(m_qWriteRequests != null); // This method supports the method callback version of the IAsyncResult APM only; therefore, // a callback method must always be specified and this is also why the method returns void // instead of returning an IAsyncResult if (asyncCallback == null) throw new ArgumentNullException("asyncCallback"); SyncGateAsyncResult ar = new SyncGateAsyncResult(mode, asyncCallback, asyncState); Boolean goodToGo = false; Monitor.Enter(m_syncLock); switch (mode) { case SyncGateMode.Exclusive: switch (m_state) { case SyncGateStates.Free: // If Free | RFW -> OBW, invoke, return case SyncGateStates.ReservedForWriter: m_state = SyncGateStates.OwnedByWriter; goodToGo = true; // QueueCallback(ar); break; case SyncGateStates.OwnedByReaders: // If OBR | OBRAWP -> OBRAWP, queue, return case SyncGateStates.OwnedByReadersAndWriterPending: m_state = SyncGateStates.OwnedByReadersAndWriterPending; m_qWriteRequests.Enqueue(ar); break; case SyncGateStates.OwnedByWriter: // If OBW, queue, return m_qWriteRequests.Enqueue(ar); break; } break; case SyncGateMode.Shared: switch (m_state) { case SyncGateStates.Free: // If Free | OBR -> OBR, NR++, invoke, return case SyncGateStates.OwnedByReaders: m_state = SyncGateStates.OwnedByReaders; m_numReaders++; goodToGo = true; // QueueCallback(ar); break; case SyncGateStates.OwnedByWriter: // If OBW | OBRAWP | RFW, queue, return case SyncGateStates.OwnedByReadersAndWriterPending: case SyncGateStates.ReservedForWriter: m_qReadRequests.Enqueue(ar); break; } break; } Monitor.Exit(m_syncLock); if (goodToGo) ar.SetAsCompleted(null, true); }
private static void QueueCallback(SyncGateAsyncResult sgar) { ThreadPool.QueueUserWorkItem(InvokeCallback, sgar); }
private static void QueueCallback(SyncGateAsyncResult sgar) { ThreadPool.QueueUserWorkItem(InvokeCallback, sgar); }
/// <summary> /// Allows the caller to notify the SyncGate that it wants exclusive or shared access to a resource. /// </summary> /// <param name="mode">Indicates if exclusive or shared access is desired.</param> /// <param name="asyncCallback">The callback method to invoke once access can be granted.</param> /// <param name="asyncState">Additional state to pass to the callback method.</param> public void BeginRegion(SyncGateMode mode, AsyncCallback asyncCallback, Object asyncState) { Contract.Assume(m_qReadRequests != null); Contract.Assume(m_qWriteRequests != null); // This method supports the method callback version of the IAsyncResult APM only; therefore, // a callback method must always be specified and this is also why the method returns void // instead of returning an IAsyncResult if (asyncCallback == null) { throw new ArgumentNullException("asyncCallback"); } SyncGateAsyncResult ar = new SyncGateAsyncResult(mode, asyncCallback, asyncState); Boolean goodToGo = false; Monitor.Enter(m_syncLock); switch (mode) { case SyncGateMode.Exclusive: switch (m_state) { case SyncGateStates.Free: // If Free | RFW -> OBW, invoke, return case SyncGateStates.ReservedForWriter: m_state = SyncGateStates.OwnedByWriter; goodToGo = true; // QueueCallback(ar); break; case SyncGateStates.OwnedByReaders: // If OBR | OBRAWP -> OBRAWP, queue, return case SyncGateStates.OwnedByReadersAndWriterPending: m_state = SyncGateStates.OwnedByReadersAndWriterPending; m_qWriteRequests.Enqueue(ar); break; case SyncGateStates.OwnedByWriter: // If OBW, queue, return m_qWriteRequests.Enqueue(ar); break; } break; case SyncGateMode.Shared: switch (m_state) { case SyncGateStates.Free: // If Free | OBR -> OBR, NR++, invoke, return case SyncGateStates.OwnedByReaders: m_state = SyncGateStates.OwnedByReaders; m_numReaders++; goodToGo = true; // QueueCallback(ar); break; case SyncGateStates.OwnedByWriter: // If OBW | OBRAWP | RFW, queue, return case SyncGateStates.OwnedByReadersAndWriterPending: case SyncGateStates.ReservedForWriter: m_qReadRequests.Enqueue(ar); break; } break; } Monitor.Exit(m_syncLock); if (goodToGo) { ar.SetAsCompleted(null, true); } }