Request Queue

来源:互联网 发布:淘宝能开蛋糕店吗 编辑:程序博客网 时间:2024/06/14 04:19
  1. // ==++==
  2. // 
  3. //   
  4. //    Copyright (c) 2002 Microsoft Corporation.  All rights reserved.
  5. //   
  6. //    The use and distribution terms for this software are contained in the file
  7. //    named license.txt, which can be found in the root of this distribution.
  8. //    By using this software in any fashion, you are agreeing to be bound by the
  9. //    terms of this license.
  10. //   
  11. //    You must not remove this notice, or any other, from this software.
  12. //   
  13. // 
  14. // ==--==
  15. //
  16. // Request Queue
  17. //      queues up the requests to avoid thread pool starvation,
  18. //      making sure that there are always available threads to process requests
  19. namespace System.Runtime.Remoting.Channels {
  20.     using System.Threading;
  21.     using System.Collections;
  22.     internal class RequestQueue {
  23.         // configuration params
  24.         private int _minExternFreeThreads;
  25.         private int _minLocalFreeThreads;
  26.         private int _queueLimit;
  27.         // two queues -- one for local requests, one for external
  28.         private Queue _localQueue = new Queue();
  29.         private Queue _externQueue = new Queue();
  30.         // total count
  31.         private int _count;
  32.         // work items queued to pick up new work
  33.         private WaitCallback _workItemCallback;
  34.         private int _workItemCount;
  35.         private const int _workItemLimit = 2;
  36.         private bool _draining;
  37.         // helpers
  38.         private static bool IsLocal(SocketHandler sh) {
  39.             return sh.IsLocal();
  40.         }
  41.         private void QueueRequest(SocketHandler sh, bool isLocal) {
  42.             lock (this) {
  43.                 if (isLocal)
  44.                     _localQueue.Enqueue(sh);
  45.                 else 
  46.                     _externQueue.Enqueue(sh);
  47.                 _count++;
  48.             }
  49.         }
  50.         private SocketHandler DequeueRequest(bool localOnly) {
  51.             Object sh = null;
  52.             if (_count > 0) {
  53.                 lock (this) {
  54.                     if (_localQueue.Count > 0) {
  55.                         sh = _localQueue.Dequeue();
  56.                         _count--;
  57.                     }
  58.                     else if (!localOnly && _externQueue.Count > 0) {
  59.                         sh = _externQueue.Dequeue();
  60.                         _count--;
  61.                     }
  62.                 }
  63.             }
  64.             return (SocketHandler)sh;
  65.         }
  66.         // ctor
  67.         internal RequestQueue(int minExternFreeThreads, int minLocalFreeThreads, int queueLimit) {
  68.             _minExternFreeThreads = minExternFreeThreads;
  69.             _minLocalFreeThreads = minLocalFreeThreads;
  70.             _queueLimit = queueLimit;
  71.             
  72.             _workItemCallback = new WaitCallback(this.WorkItemCallback);
  73.         }
  74.         // method called to process the next request
  75.         internal void ProcessNextRequest(SocketHandler sh)
  76.         {
  77.             sh = GetRequestToExecute(sh);
  78.             if (sh != null)
  79.                 sh.ProcessRequestNow();
  80.         } // ProcessNextRequest
  81.         
  82.         // method called when data arrives for incoming requests
  83.         internal SocketHandler GetRequestToExecute(SocketHandler sh) {
  84.             int workerThreads, ioThreads;
  85.             ThreadPool.GetAvailableThreads(out workerThreads, out ioThreads);
  86.             int freeThreads = (ioThreads > workerThreads) ? workerThreads : ioThreads;
  87.             // fast path when there are threads available and nothing queued
  88.             if (freeThreads >= _minExternFreeThreads && _count == 0)
  89.                 return sh;
  90.             bool isLocal = IsLocal(sh);
  91.             // fast path when there are threads for local requests available and nothing queued
  92.             if (isLocal && freeThreads >= _minLocalFreeThreads && _count == 0)
  93.                 return sh;
  94.             // reject if queue limit exceeded
  95.             if (_count >= _queueLimit) {
  96.                 sh.RejectRequestNowSinceServerIsBusy();
  97.                 return null;
  98.             }
  99.             // can't execute the current request on the current thread -- need to queue
  100.             QueueRequest(sh, isLocal);
  101.             // maybe can execute a request previously queued
  102.             if (freeThreads >= _minExternFreeThreads) {
  103.                 sh = DequeueRequest(false); // enough threads to process even external requests
  104.             }
  105.             else if (freeThreads >= _minLocalFreeThreads) {
  106.                 sh = DequeueRequest(true);  // enough threads to process only local requests
  107.             }
  108.             else {
  109.                 sh = null;                  // not enough threads -> do nothing on this thread
  110.                 ScheduleMoreWorkIfNeeded(); // try to schedule to worker thread
  111.             }
  112.             return sh;
  113.         }
  114.         // method called from SocketHandler at the end of request
  115.         internal void ScheduleMoreWorkIfNeeded() {
  116.             // too late for more work if draining
  117.             if (_draining)
  118.                 return;
  119.             // is queue empty?
  120.             if (_count == 0)
  121.                 return;
  122.             // already scheduled enough work items
  123.             if (_workItemCount >= _workItemLimit)
  124.                 return;
  125.             // queue the work item
  126.             Interlocked.Increment(ref _workItemCount);
  127.             ThreadPool.QueueUserWorkItem(_workItemCallback);
  128.         }
  129.         // is empty property
  130.         internal bool IsEmpty {
  131.             get { return (_count == 0); }
  132.         }
  133.         // method called to pick up more work
  134.         private void WorkItemCallback(Object state) {
  135.             Interlocked.Decrement(ref _workItemCount);
  136.             // too late for more work if draining
  137.             if (_draining)
  138.                 return;
  139.             // is queue empty?
  140.             if (_count == 0)
  141.                 return;
  142.             int workerThreads, ioThreads;
  143.             ThreadPool.GetAvailableThreads(out workerThreads, out ioThreads);
  144.             bool bHandledRequest = false;
  145.             // service another request if enough worker threads are available
  146.             if (workerThreads >= _minLocalFreeThreads)
  147.             {
  148.                 // pick up request from the queue
  149.                 SocketHandler sh = DequeueRequest(workerThreads < _minExternFreeThreads);
  150.                 if (sh != null)
  151.                 {
  152.                     sh.ProcessRequestNow();
  153.                     bHandledRequest = true;
  154.                 }
  155.             }
  156.             if (!bHandledRequest)            
  157.                 ScheduleMoreWorkIfNeeded();
  158.         }
  159.         // reject all requests
  160.         internal void Drain() {
  161.             _draining = true;
  162.             // wait for all work items to finish
  163.             while (_workItemCount > 0)
  164.                 Thread.Sleep(100);
  165.             // is queue empty?
  166.             if (_count == 0)
  167.                 return;
  168.             for (;;) {
  169.                 SocketHandler sh = DequeueRequest(false);
  170.                 if (sh == null)
  171.                     break;
  172.                 sh.RejectRequestNowSinceServerIsBusy();
  173.             }
  174.         }
  175.     }
  176. }