像这样的事情?
using Timer = System.Threading.Timer;
class Limiter{
public static readonly Limiter Instance = new Limiter();
Limiter(){}
int max;
Semaphore counter;
List<Timer> timers = new List<Timer>();
// warning: not thread safe!
public int MaxExecutionPerSecond{
get{return max;}
set{counter = new Semaphore(max = value, value);}
}
public void WaitIfRequired(){
// Our semaphore starts with a count of MaxExecutionPerSecond.
// When we call WaitOne(), it decrements the count. If the count
// is already zero, the call to WaitOne() will block until another
// thread calls Release() to increment the count.
counter.WaitOne();
// Set a timer to increment the semaphore in one second.
Timer t = null;
t = new Timer(o=>{
// Increment the semaphore.
counter.Release();
// We no longer need to protect this timer from the GC.
timers.Remove(t);
t.Dispose();
});
// Hold a reference to this timer to keep it from being disposed of.
timers.Add(t);
// Set the timer to release the semaphore in one second.
t.Change(1000, Timeout.Infinite);
}
}
编辑
有一点要记住的是,上面的代码只能防止多个线程开始一次。如果线程长时间运行,那么一次运行的许多线程仍然是可能的。例如,如果你每秒启动5个线程,但每个线程运行1秒,那么在2秒后的任何给定时间,理论上你将有10个线程在运行。
如果你想确保你永远不会有超过5个线程同时运行,最简单的事情就是免去自定义类Limiter
,直接使用Semaphore
。
const int maxThreadCount = 5;
static Semaphore counter = new Semaphore(maxThreadCount, maxThreadCount);
static void NewThread(object state){
counter.WaitOne();
// do something
counter.Release();
}
现在,这只是简单的,因为它可以。但有一点需要注意:创建新线程并立即让它们睡觉通常被认为是一个坏主意。这使用系统资源来创建一个没有任何作用的线程。最好排队请求并启动新线程(或者更好的是,使用线程池线程)来处理它们,直到它们有资格运行。这是更复杂和更难以正确。根据设计的不同,它可能需要额外的调度程序/管理线程。事情是这样的:
class Limiter{
class WorkData{
readonly ParameterizedThreadStart action;
readonly object data;
public ParameterizedThreadStart Action{get{return action;}}
public object Data {get{return data;}}
public WorkData(ParameterizedThreadStart action, object data){
this.action = action;
this.data = data;
}
}
readonly Semaphore threadCount;
readonly Queue<WorkData> workQueue = new Queue<WorkData>();
readonly Semaphore queueCount = new Semaphore(0, int.MaxValue);
public Limiter(int maxThreadCount){
threadCount = new Semaphore(maxThreadCount, maxThreadCount);
Thread t = new Thread(StartWorkItems);
t.IsBackground = true;
t.Start();
}
void StartWorkItems(object ignored){
while(queueCount.WaitOne() && threadCount.WaitOne()){
WorkData wd;
lock(workQueue)
wd = workQueue.Dequeue();
ThreadPool.QueueUserWorkItem(DoWork, wd);
}
}
void DoWork(object state){
WorkData wd = (WorkData)state;
wd.Action(wd.Data);
counter.Release();
}
public void QueueWork(ParameterizedThreadStart action, object data){
lock(workQueue)
workQueue.Enqueue(new WorkData(action, data));
queueCount.Release();
}
}
在这个类中,我已经去除了单属性和给定的构造函数maxThreadCount
参数。这样可以避免第一类资产缺乏线程安全性。还有其他方法可以添加线程安全性,但这是最简单的。
了解CCR? (http://msdn.microsoft.com/en-us/library/bb648752.aspx) – 2010-02-20 13:21:45