2008-03-05 09:52:00 -05:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Microsoft Research Singularity
|
|
|
|
//
|
|
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
//
|
|
|
|
// Note:
|
|
|
|
//
|
|
|
|
using System;
|
|
|
|
using System.Collections;
|
|
|
|
using System.Threading;
|
|
|
|
#if SINGULARITY
|
|
|
|
using Microsoft.Contracts;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace Microsoft.Singularity.Applications
|
|
|
|
{
|
|
|
|
/// <remarks>This class implements a non-Singleton
|
|
|
|
/// threadpool and has a configurable work queue
|
|
|
|
/// size. </remarks>
|
|
|
|
public sealed class ThreadPool
|
|
|
|
{
|
|
|
|
internal class WorkItem {
|
|
|
|
public WorkCallback callback;
|
|
|
|
public object userObject;
|
|
|
|
|
|
|
|
public WorkItem(WorkCallback callback, object userObject)
|
|
|
|
{
|
|
|
|
this.callback = callback;
|
|
|
|
this.userObject = userObject;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public delegate void WorkCallback(object userObject);
|
|
|
|
|
|
|
|
Queue /* ! */ workItems;
|
|
|
|
WorkCallback /* ! */ workCallback;
|
|
|
|
int maxQueuedItems;
|
|
|
|
volatile int threadCount;
|
|
|
|
volatile bool shutdown;
|
|
|
|
ManualResetEvent shutdownEvent;
|
|
|
|
|
|
|
|
#if SINGULARITY
|
|
|
|
[NotDelayed]
|
|
|
|
#endif
|
|
|
|
public ThreadPool(int maxThreads,
|
|
|
|
int maxQueuedItems,
|
|
|
|
WorkCallback/* ! */ workCallback)
|
|
|
|
#if SINGULARITY
|
|
|
|
requires maxThreads > 0;
|
|
|
|
requires maxQueuedItems > 0;
|
|
|
|
requires maxThreads <= maxQueuedItems;
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
this.workCallback = workCallback;
|
|
|
|
this.workItems = new Queue(maxQueuedItems);
|
|
|
|
this.maxQueuedItems = maxQueuedItems;
|
|
|
|
this.threadCount = maxThreads;
|
|
|
|
this.shutdown = false;
|
|
|
|
this.shutdownEvent = new ManualResetEvent(false);
|
|
|
|
#if SINGULARITY
|
|
|
|
base();
|
|
|
|
#endif
|
|
|
|
for (int i = 0; i < maxThreads; i++) {
|
|
|
|
Thread t = new Thread(new ThreadStart(WorkerMain));
|
|
|
|
t.Start();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Queues call to constructor supplied delegate with
|
|
|
|
/// user supplied object. If queuing request causes queue to
|
|
|
|
/// become full, false is returned and no further items should
|
|
|
|
/// be enqueued until delegate has been called.
|
|
|
|
/// </summary>
|
|
|
|
public bool QueueUserWorkItem(object userObject)
|
|
|
|
{
|
|
|
|
bool queueIsFull = false;
|
|
|
|
lock (this) {
|
|
|
|
if (workItems.Count == maxQueuedItems) {
|
|
|
|
queueIsFull = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
#if SINGULARITY
|
|
|
|
assert workItems.Count < maxQueuedItems;
|
|
|
|
assert shutdown == false;
|
|
|
|
#endif
|
|
|
|
WorkItem work = new WorkItem(this.workCallback, userObject);
|
|
|
|
workItems.Enqueue(work);
|
|
|
|
queueIsFull = (workItems.Count == maxQueuedItems);
|
2008-11-17 18:29:00 -05:00
|
|
|
if (workItems.Count == 1) {
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
Monitor.Pulse(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return queueIsFull;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Queues call to supplied delegate with
|
|
|
|
/// user supplied object. If queuing request causes queue to
|
|
|
|
/// become full, false is returned and no further items should
|
|
|
|
/// be enqueued until delegate has been called.
|
|
|
|
/// </summary>
|
|
|
|
public bool QueueUserWorkItem(WorkCallback callback, object userObject)
|
|
|
|
{
|
|
|
|
bool queueIsFull = false;
|
|
|
|
lock (this) {
|
|
|
|
if (workItems.Count == maxQueuedItems) {
|
|
|
|
queueIsFull = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
#if SINGULARITY
|
|
|
|
assert workItems.Count < maxQueuedItems;
|
|
|
|
assert shutdown == false;
|
|
|
|
#endif
|
|
|
|
WorkItem work = new WorkItem(callback, userObject);
|
|
|
|
workItems.Enqueue(work);
|
|
|
|
queueIsFull = (workItems.Count == maxQueuedItems);
|
2008-11-17 18:29:00 -05:00
|
|
|
if (workItems.Count == 1) {
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
Monitor.Pulse(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return queueIsFull;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Shutdown thread pool instance. Caller blocks until
|
|
|
|
/// the threads in the pool have finished outstanding
|
|
|
|
/// work items.
|
|
|
|
/// </summary>
|
|
|
|
public void Shutdown()
|
|
|
|
{
|
|
|
|
lock (this) {
|
|
|
|
shutdown = true;
|
|
|
|
Monitor.PulseAll(this);
|
|
|
|
}
|
|
|
|
shutdownEvent.WaitOne();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void WorkerMain()
|
|
|
|
{
|
|
|
|
while (true) {
|
|
|
|
object workItem = null;
|
|
|
|
lock (this) {
|
|
|
|
while (workItems.Count == 0 && !shutdown) {
|
|
|
|
Monitor.Wait(this);
|
|
|
|
}
|
|
|
|
if (workItems.Count == 0 && shutdown) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
workItem = workItems.Dequeue();
|
|
|
|
}
|
|
|
|
if (workItem != null) {
|
|
|
|
WorkItem w = workItem as WorkItem;
|
|
|
|
#if SINGULARITY
|
|
|
|
assert w != null;
|
|
|
|
assert w.callback != null;
|
|
|
|
#endif
|
|
|
|
w.callback(w.userObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (--threadCount == 0) {
|
|
|
|
shutdownEvent.Set();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|