////////////////////////////////////////////////////////////////////////////////
// WorkerPool - A wrapper around the BackgroundWorker class.
//
// Copyright (c) 2008 Jose Simas (josesimas at gepsoft.com). All Rights Reserved.
//
// Permission to use, copy, modify, and distribute this software and its
// documentation for any purpose, without fee, and without a written
// agreement, is hereby granted, provided that the above copyright notice,
// this paragraph and the following two paragraphs appear in all copies,
// modifications, and distributions.
//
// IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
// PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
// EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
// ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION
// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
//
// V0.9 23/01/2008 - First release for comments
////////////////////////////////////////////////////////////////////////////////
namespace Gepsoft.WorkerPool
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
///
/// Maintains a list of workers and manages their lifetimes.
///
/// Can be called from any thread.
///
public static class WorkerPool
{
private static readonly IList _workers = new List();
///
/// Returns the next free worker or a new worker if all the
/// existing ones are busy.
///
public static Worker Next
{
get
{
lock (typeof(WorkerPool))
{
var nextFreeWorker = from w in _workers where ! w.IsBusy select w;
if (nextFreeWorker.Count() == 0)
{
_workers.Add(new Worker());
return _workers[_workers.Count - 1];
}
var worker = nextFreeWorker.First();
((IDisposable)worker).Dispose();
return worker;
}
}
}
///
/// The number of active workers in the pool.
///
public static int Count
{
get
{
lock (typeof(WorkerPool))
return _workers.Count;
}
}
///
/// It is true if any of the workers in the pool is busy.
///
public static bool IsBusy
{
get
{
lock (typeof (WorkerPool))
return (from w in _workers where w.IsBusy select w).Count() > 0;
}
}
///
/// Disposes all workers and clears the pool. Usually you are not required
/// to call this method but it may be useful for debugging or when trying
/// to recover from a general exception.
///
public static void Clear()
{
lock (typeof(WorkerPool))
{
foreach (IDisposable w in _workers)
w.Dispose();
_workers.Clear();
}
}
///
/// Wrapper for the BackgroundWorker class.
///
/// The difference is that this class supports a fluent interface, is
/// managed by the WorkerPool class and supports passing multiple
/// parameters to the background thread.
///
public class Worker : IDisposable
{
//No direct instantiation allowed. Get instances through the WorkerPool
internal Worker()
{
}
///
/// This delegate simplifies calls when there is no need to pass arguments and the sender.
///
public delegate void NoArgsEventHandler();
///
/// This delegate simplifies calls when there is no need to pass the sender.
///
public delegate void ArgsOnlyDoWorkEventHandler(DoWorkEventArgs e);
///
/// This delegate simplifies calls when there is no need to pass the sender.
///
public delegate void ArgsOnlyOnFinishedEventHandler(RunWorkerCompletedEventArgs e);
//private data
private BackgroundWorker _worker;
readonly IList