线程池(Thread Pooling)

来源:互联网 发布:淘宝掌柜信用评分下降 编辑:程序博客网 时间:2024/05/16 01:35

线程池(Thread Pooling)

    如果你的应用程序拥有大量的线程并花费大量的时间阻塞在一个Wait Handle上,那么你要考虑使用线程池(Thead pooling)来处理。线程池通过合并多个Wait Handle来节约等待的时间。当Wait Handle被激活时,使用线程池你需要注册一个Wait Handle到一个委托去执行。通过调用ThreadPool.RegisterWaitForSingleObject方法:

class Test 
{
static ManualResetEvent starter = new ManualResetEvent(false);

public static void Main()
{
ThreadPool.RegisterWaitForSingleObject(starter, Go, "hello", -1, true);
Thread.Sleep(5000);
Console.WriteLine("Signaling worker...");
starter.Set();
Console.ReadLine();
}

public static void Go(object data, bool timedOut)
{
Console.WriteLine("Started " + data);
// Perform task...
}
}

    对于Wait Handle和委托,RegisterWaitForSingleObject接受一个"黑盒"对象并传递给你的委托(就像ParameterizedThreadStart),超时设置和boolean标志指示了关闭和循环的请求。所有进入池中的线程都被认为是后台线程,这就意味着它们不再由应用程序控制,而是由系统控制直到应用程序退出。

    注意:如果这时候调用Abort操作,可能会发生意想不到的情况。
  
   你也可以通过调用QueueUserWorkItem方法使用线程池,指定委托并立即被执行。这时你不能在多任务情况下保存共享线程,但是可以得到另外的好处:线程池会保持一个线程的总容量,当作业数超出容量时自动插入任务。

class Test 
{
static object workerLocker = new object();
static int runningWorkers = 100;

public static void Main()
{
for (int i = 0; i < runningWorkers; i++)
{
ThreadPool.QueueUserWorkItem(Go, i);
}
Console.WriteLine("Waiting for threads to complete...");
lock (workerLocker)
{
while (runningWorkers > 0) Monitor.Wait(workerLocker);
}
Console.WriteLine("Complete!");
Console.ReadLine();
}

public static void Go(object instance)
{
Console.WriteLine("Started: " + instance);
Thread.Sleep(1000);
Console.WriteLine("Ended: " + instance);
lock (workerLocker)
{
runningWorkers--; Monitor.Pulse(workerLocker);
}
}
}

    为了传递多个对象到目标方法,你必须定义一个客户对象并包含所有属性或通过调用异步的委托。如Go方法接受两参数: 

ThreadPool.QueueUserWorkItem (delegate (object notUsed) { Go (23,34); }); 


    其他的方法可以使用异步委托。

 

 

 

 

其实对于OpenExisting函数有两个重载版本,
   Mutex.OpenExisting (String)
   Mutex.OpenExisting (String, MutexRights) 
   对于默认的第一个函数其实是实现了第二个函数 MutexRights.Synchronize|MutexRights.Modify操作。

    由于监视器的设计是基于.Net框架,而Mutex类是系统内核对象封装了win32的一个内核结构来实现互斥,并且互斥操作需要请求中断来完成,因此在进行进程内线程同步的时候性能上要比互斥要好。

    典型的使用Mutex同步需要完成三个步骤的操作:1.打开或者创建一个Mutex实例;2.调用WaitOne()来请求互斥对象;3.最后调用ReleaseMutex来释放互斥对象。

static public void AddString(string str) 
{
// 设置超时时限并在wait前退出非默认托管上下文
if (_mtx.WaitOne(1000, true))
{
_resource.Add(str);
_mtx.ReleaseMutex();
}
}

    需要注意的是,WaitOne和ReleaseMutex必须成对出现,否则会导致进程死锁的发生,这时系统(.Net2.0)框架会抛出AbandonedMutexException异常。

信号量(Semaphore)

    信号量就像一个夜总会:它有确切的容量,并被保镖控制。一旦满员,就没有人能再进入,其他人必须在外面排队。那么在里面离开一个人后,队头的人就可以进入。信号量的构造函数需要提供至少两个参数-现有的人数和最大的人数。
信号量的行为有点类似于Mutex或是lock,但是信号量没有拥有者。任意线程都可以调用Release来释放信号量而不像Mutex和lock那样需要线程得到资源才能释放。

class SemaphoreTest 
{
static Semaphore s = new Semaphore(3, 3); // 当前值=3; 容量=3

static void Main()
{
for (int i = 0; i < 10; i++) new Thread(Go).Start();
}

static void Go()
{
while (true)
{
s.WaitOne();
Thread.Sleep(100); // 一次只有个线程能被处理
s.Release();
}
}
}
原创粉丝点击