- // ==++==
- //
- //
- // Copyright (c) 2002 Microsoft Corporation. All rights reserved.
- //
- // The use and distribution terms for this software are contained in the file
- // named license.txt, which can be found in the root of this distribution.
- // By using this software in any fashion, you are agreeing to be bound by the
- // terms of this license.
- //
- // You must not remove this notice, or any other, from this software.
- //
- //
- // ==--==
- //
- // Request Queue
- // queues up the requests to avoid thread pool starvation,
- // making sure that there are always available threads to process requests
- namespace System.Runtime.Remoting.Channels {
- using System.Threading;
- using System.Collections;
- internal class RequestQueue {
- // configuration params
- private int _minExternFreeThreads;
- private int _minLocalFreeThreads;
- private int _queueLimit;
- // two queues -- one for local requests, one for external
- private Queue _localQueue = new Queue();
- private Queue _externQueue = new Queue();
- // total count
- private int _count;
- // work items queued to pick up new work
- private WaitCallback _workItemCallback;
- private int _workItemCount;
- private const int _workItemLimit = 2;
- private bool _draining;
- // helpers
- private static bool IsLocal(SocketHandler sh) {
- return sh.IsLocal();
- }
- private void QueueRequest(SocketHandler sh, bool isLocal) {
- lock (this) {
- if (isLocal)
- _localQueue.Enqueue(sh);
- else
- _externQueue.Enqueue(sh);
- _count++;
- }
- }
- private SocketHandler DequeueRequest(bool localOnly) {
- Object sh = null;
- if (_count > 0) {
- lock (this) {
- if (_localQueue.Count > 0) {
- sh = _localQueue.Dequeue();
- _count--;
- }
- else if (!localOnly && _externQueue.Count > 0) {
- sh = _externQueue.Dequeue();
- _count--;
- }
- }
- }
- return (SocketHandler)sh;
- }
- // ctor
- internal RequestQueue(int minExternFreeThreads, int minLocalFreeThreads, int queueLimit) {
- _minExternFreeThreads = minExternFreeThreads;
- _minLocalFreeThreads = minLocalFreeThreads;
- _queueLimit = queueLimit;
- _workItemCallback = new WaitCallback(this.WorkItemCallback);
- }
- // method called to process the next request
- internal void ProcessNextRequest(SocketHandler sh)
- {
- sh = GetRequestToExecute(sh);
- if (sh != null)
- sh.ProcessRequestNow();
- } // ProcessNextRequest
- // method called when data arrives for incoming requests
- internal SocketHandler GetRequestToExecute(SocketHandler sh) {
- int workerThreads, ioThreads;
- ThreadPool.GetAvailableThreads(out workerThreads, out ioThreads);
- int freeThreads = (ioThreads > workerThreads) ? workerThreads : ioThreads;
- // fast path when there are threads available and nothing queued
- if (freeThreads >= _minExternFreeThreads && _count == 0)
- return sh;
- bool isLocal = IsLocal(sh);
- // fast path when there are threads for local requests available and nothing queued
- if (isLocal && freeThreads >= _minLocalFreeThreads && _count == 0)
- return sh;
- // reject if queue limit exceeded
- if (_count >= _queueLimit) {
- sh.RejectRequestNowSinceServerIsBusy();
- return null;
- }
- // can't execute the current request on the current thread -- need to queue
- QueueRequest(sh, isLocal);
- // maybe can execute a request previously queued
- if (freeThreads >= _minExternFreeThreads) {
- sh = DequeueRequest(false); // enough threads to process even external requests
- }
- else if (freeThreads >= _minLocalFreeThreads) {
- sh = DequeueRequest(true); // enough threads to process only local requests
- }
- else {
- sh = null; // not enough threads -> do nothing on this thread
- ScheduleMoreWorkIfNeeded(); // try to schedule to worker thread
- }
- return sh;
- }
- // method called from SocketHandler at the end of request
- internal void ScheduleMoreWorkIfNeeded() {
- // too late for more work if draining
- if (_draining)
- return;
- // is queue empty?
- if (_count == 0)
- return;
- // already scheduled enough work items
- if (_workItemCount >= _workItemLimit)
- return;
- // queue the work item
- Interlocked.Increment(ref _workItemCount);
- ThreadPool.QueueUserWorkItem(_workItemCallback);
- }
- // is empty property
- internal bool IsEmpty {
- get { return (_count == 0); }
- }
- // method called to pick up more work
- private void WorkItemCallback(Object state) {
- Interlocked.Decrement(ref _workItemCount);
- // too late for more work if draining
- if (_draining)
- return;
- // is queue empty?
- if (_count == 0)
- return;
- int workerThreads, ioThreads;
- ThreadPool.GetAvailableThreads(out workerThreads, out ioThreads);
- bool bHandledRequest = false;
- // service another request if enough worker threads are available
- if (workerThreads >= _minLocalFreeThreads)
- {
- // pick up request from the queue
- SocketHandler sh = DequeueRequest(workerThreads < _minExternFreeThreads);
- if (sh != null)
- {
- sh.ProcessRequestNow();
- bHandledRequest = true;
- }
- }
- if (!bHandledRequest)
- ScheduleMoreWorkIfNeeded();
- }
- // reject all requests
- internal void Drain() {
- _draining = true;
- // wait for all work items to finish
- while (_workItemCount > 0)
- Thread.Sleep(100);
- // is queue empty?
- if (_count == 0)
- return;
- for (;;) {
- SocketHandler sh = DequeueRequest(false);
- if (sh == null)
- break;
- sh.RejectRequestNowSinceServerIsBusy();
- }
- }
- }
- }
Request Queue
最新推荐文章于 2022-02-23 15:02:25 发布