8b9b85e7f5
Former-commit-id: 172c8e3c300b39d5785c7a3e8dfb08ebdbc1a99b
171 lines
4.4 KiB
C#
171 lines
4.4 KiB
C#
//
|
|
// System.Runtime.Remoting.Channels.RemotingThreadPool.cs
|
|
//
|
|
// Author: Lluis Sanchez Gual (lluis@ximian.com)
|
|
//
|
|
// 2005 (C) Copyright, Novell, Inc.
|
|
//
|
|
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Threading;
|
|
|
|
namespace System.Runtime.Remoting.Channels
|
|
{
|
|
internal class RemotingThreadPool
|
|
{
|
|
const int ThreadLimit = 1000;
|
|
const int ThreadWaitTime = 20000; //ms
|
|
const int PoolGrowDelay = 500; // ms
|
|
const int MinThreads = 3;
|
|
|
|
int freeThreads;
|
|
int poolUsers;
|
|
Queue workItems = new Queue ();
|
|
AutoResetEvent threadDone = new AutoResetEvent (false);
|
|
ArrayList runningThreads = new ArrayList ();
|
|
|
|
bool stopped = false;
|
|
|
|
static object globalLock = new object ();
|
|
static RemotingThreadPool sharedPool;
|
|
|
|
public static RemotingThreadPool GetSharedPool ()
|
|
{
|
|
lock (globalLock) {
|
|
if (sharedPool == null)
|
|
sharedPool = new RemotingThreadPool ();
|
|
sharedPool.poolUsers++;
|
|
}
|
|
return sharedPool;
|
|
}
|
|
|
|
public void Free ()
|
|
{
|
|
lock (globalLock) {
|
|
if (--poolUsers > 0)
|
|
return;
|
|
|
|
lock (workItems) {
|
|
stopped = true;
|
|
threadDone.Set ();
|
|
workItems.Clear ();
|
|
foreach (Thread t in runningThreads)
|
|
t.Abort ();
|
|
runningThreads.Clear ();
|
|
}
|
|
if (this == sharedPool)
|
|
sharedPool = null;
|
|
}
|
|
}
|
|
|
|
public bool RunThread (ThreadStart threadStart)
|
|
{
|
|
lock (workItems) {
|
|
if (stopped)
|
|
throw new RemotingException ("Server channel stopped.");
|
|
|
|
if (freeThreads > 0) {
|
|
freeThreads--;
|
|
workItems.Enqueue (threadStart);
|
|
Monitor.Pulse (workItems);
|
|
return true;
|
|
} else if (runningThreads.Count < MinThreads) {
|
|
workItems.Enqueue (threadStart);
|
|
StartPoolThread ();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Try again some ms later, and if there are still no free threads,
|
|
// then create a new one
|
|
|
|
threadDone.WaitOne (PoolGrowDelay, false);
|
|
|
|
lock (workItems) {
|
|
if (stopped)
|
|
throw new RemotingException ("Server channel stopped.");
|
|
|
|
if (freeThreads > 0) {
|
|
freeThreads--;
|
|
workItems.Enqueue (threadStart);
|
|
Monitor.Pulse (workItems);
|
|
} else {
|
|
if (runningThreads.Count >= ThreadLimit)
|
|
return false;
|
|
workItems.Enqueue (threadStart);
|
|
StartPoolThread ();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void StartPoolThread ()
|
|
{
|
|
Thread thread = new Thread (new ThreadStart (PoolThread));
|
|
runningThreads.Add (thread);
|
|
thread.IsBackground = true;
|
|
thread.Start ();
|
|
}
|
|
|
|
void PoolThread ()
|
|
{
|
|
while (true) {
|
|
ThreadStart work = null;
|
|
do {
|
|
lock (workItems) {
|
|
if (workItems.Count > 0)
|
|
work = (ThreadStart) workItems.Dequeue ();
|
|
else {
|
|
freeThreads ++;
|
|
threadDone.Set ();
|
|
if (!Monitor.Wait (workItems, ThreadWaitTime)) {
|
|
// Maybe it timed out when the work was being queued.
|
|
if (workItems.Count > 0) {
|
|
work = (ThreadStart) workItems.Dequeue ();
|
|
} else {
|
|
freeThreads --;
|
|
if (freeThreads == 0) threadDone.Reset ();
|
|
runningThreads.Remove (Thread.CurrentThread);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while (work == null);
|
|
try {
|
|
work ();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
#if DEBUG
|
|
Console.WriteLine("The exception was caught during RemotingThreadPool.PoolThread - work: {0}, {1}", ex.GetType(), ex.Message);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|