C#多线程实现方法——线程池(Thread Pool)

  1. ThreadPool使用
  2. 同步机制

ThreadPool使用

需要定义waitcallback委托形式如

[csharp] view plain copy

print?

  1. public delegate void WaitCallback(object state);
public delegate void WaitCallback(object state);

例如如下例子:

[csharp] view plain copy

print?

  1. static private void ThreadWorker(object state)
  2. {
  3. int num = (int)state;
  4. if (num > 0)
  5. {
  6. for (int i = 0; i < 3; i++)
  7. {
  8. Thread.Sleep(1000);// sleep for one second
  9. num++;
  10. Console.WriteLine(string.Format("Current thread {0} deal with {1}.", Thread.CurrentThread.ManagedThreadId, num));
  11. }
  12. }
  13. return;
  14. }
        static private void ThreadWorker(object state)
        {
            int num = (int)state;
            if (num > 0)
            {
                for (int i = 0; i < 3; i++)
                {
                    Thread.Sleep(1000);// sleep for one second
                    num++;
                    Console.WriteLine(string.Format("Current thread {0} deal with {1}.", Thread.CurrentThread.ManagedThreadId, num));
                }
            }
            return;
        }

就是一个简单的隔一秒增加一的自增器。

调用ThreadPool的方法很简单,需要引用System.Threading。接着使用QueueUserWorkItem或者UnsafeQueueUserWorkerItem。

[csharp] view plain copy

print?

  1. public  static  class  Th read Pool  {
  2. }
  3. public  static  bool  QueueUserWorkltem (WaitCa llback  ca llBack) ;
  4. public  stat ic  bool  QueueUserWork ltem (
  5. WaitCallback  callBack,
  6. object  state
  7. ) ;
  8. [Secu rityPermi ssion (Secu rityAction .Lin kDemand,  Flags=
  9. Secu rityPermi ssionFlag . ControlPol icy l
  10. Secu rityPermi ssionF lag . Cont rolEvidence )]
  11. public  stat ic  bool  UnsafeQueueUserWorkltem (
  12. WaitCallback  callBac k,
  13. obj ect  state
  14. ) ;
public  static  class  Th read Pool  {
}
public  static  bool  QueueUserWorkltem (WaitCa llback  ca llBack) ;
public  stat ic  bool  QueueUserWork ltem (
WaitCallback  callBack,
object  state
) ;
[Secu rityPermi ssion (Secu rityAction .Lin kDemand,  Flags=
Secu rityPermi ssionFlag . ControlPol icy l
Secu rityPermi ssionF lag . Cont rolEvidence )]
public  stat ic  bool  UnsafeQueueUserWorkltem (
WaitCallback  callBac k,
obj ect  state
) ; 

可以接受一个参数传递给异步线程。

结合前面的自增器,下面例子是申请5个异步线程来运行上述的自增器,传递的值是10,20,30,40,50。接着等待足够长的时间来等待所有线程池里的工作完成。

[csharp] view plain copy

print?

  1. for (int i = 1; i <= 5; i++)
  2. ThreadPool.QueueUserWorkItem(ThreadWorker, i * 10);
  3. for (int i = 0; i < 5; i++)
  4. Thread.Sleep(1000);// wait for all threads finish
for (int i = 1; i <= 5; i++)
                ThreadPool.QueueUserWorkItem(ThreadWorker, i * 10);
            for (int i = 0; i < 5; i++)
                Thread.Sleep(1000);// wait for all threads finish

从上面可以看到线程池的使用非常的简单,只需要提供符合waitcallback的委托的工作函数,接着调用QueueUserWorkItem或者UnsafeQueueUserWorkItem添加到线程池里就ok了。但是线程池的缺点也是有的,首先,没有简单的方法来知道工作线程已经完成了,不想asynchronous中提供那么多种等待异步结束的方法,更谈不上能够添加回调函数,也不想thread那样可以使用join函数来等待线程或者使用abort函数中断正在运行的工作项。同时由于它是后台线程,也就是意味如果没有前台线程,程序就关闭,所有正在运行的或者还留在线程池里的工作项就给强制中断。所以不能将一些类似保存退出的操作放进线程池里,因为没有保证机制能够证明所有的线程池里正在运行或者还没运行的工作项能够具有明确的行为。

同步机制

ThreadPool没有提供简单的方法来获取工作线程已经结束,所以需要通过事件或者其他的内核对象来实现同步机制。

1. 如果需要获取某一个工作线程是否结束可以使用手动事件来实现。

[csharp] view plain copy

print?

  1. static private ManualResetEvent finish = new ManualResetEvent(false);
  2. static private void ThreadWorker(object state)
  3. {
  4. {
  5. for (int i = 0; i < 5; i++)
  6. {
  7. Thread.Sleep(1000);
  8. Console.WriteLine("current thead {0} wait for {1} seconds.", Thread.CurrentThread.ManagedThreadId, i + 1);
  9. }
  10. finish.Set();
  11. }
  12. return;
  13. }
static private ManualResetEvent finish = new ManualResetEvent(false);
        static private void ThreadWorker(object state)
        {

            {
                for (int i = 0; i < 5; i++)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine("current thead {0} wait for {1} seconds.", Thread.CurrentThread.ManagedThreadId, i + 1);
                }
                finish.Set();
            }
            return;
        }

主调函数实现代码为:

[csharp] view plain copy

print?

  1. ThreadPool.QueueUserWorkItem(ThreadWorker);
  2. finish.WaitOne();
  3. finish.Close();
            ThreadPool.QueueUserWorkItem(ThreadWorker);
            finish.WaitOne();
finish.Close();

或者使用匿名委托函数加using关键字保证了事件的释放

[csharp] view plain copy

print?

  1. using (ManualResetEvent finish = new ManualResetEvent(false))
  2. {
  3. ThreadPool.QueueUserWorkItem(delegate {
  4. for (int i = 0; i < 5; i++)
  5. {
  6. Thread.Sleep(1000);
  7. Console.WriteLine("current thead {0} wait for {1} seconds.", Thread.CurrentThread.ManagedThreadId, i + 1);
  8. }
  9. finish.Set();
  10. });
  11. finish.WaitOne();
  12. }
            using (ManualResetEvent finish = new ManualResetEvent(false))
            {
                ThreadPool.QueueUserWorkItem(delegate {
                    for (int i = 0; i < 5; i++)
                    {
                        Thread.Sleep(1000);
                        Console.WriteLine("current thead {0} wait for {1} seconds.", Thread.CurrentThread.ManagedThreadId, i + 1);
                    }
                    finish.Set();
                });
                finish.WaitOne();
            }

 

2.如果需要获取多个工作线程是否结束可以通过最后一个工作线程来触发事件来实现。

如果使用前面的方法给每一个工作线程分配一个事件,然后等待所有事件给触发,是非常低效的,可以使用如下方法

[csharp] view plain copy

print?

  1. using (ManualResetEvent finish = new ManualResetEvent(false))
  2. {
  3. int nTask = 10;
  4. for (int i = 0; i < nTask; i++)
  5. {
  6. ThreadPool.QueueUserWorkItem(delegate
  7. {
  8. for (int j = 0; j < 3; j++)
  9. {
  10. Thread.Sleep(1000);
  11. Console.WriteLine("current thead {0} wait for {1} seconds.", Thread.CurrentThread.ManagedThreadId, i * 10 + j + 1);
  12. }
  13. if (Interlocked.Decrement(ref nTask) == 0)
  14. {
  15. finish.Set();
  16. }
  17. }, i);
  18. }
  19. finish.WaitOne();
  20. }
            using (ManualResetEvent finish = new ManualResetEvent(false))
            {
                int nTask = 10;
                for (int i = 0; i < nTask; i++)
                {
                    ThreadPool.QueueUserWorkItem(delegate
                    {
                        for (int j = 0; j < 3; j++)
                        {
                            Thread.Sleep(1000);
                            Console.WriteLine("current thead {0} wait for {1} seconds.", Thread.CurrentThread.ManagedThreadId, i * 10 + j + 1);
                        }
                        if (Interlocked.Decrement(ref nTask) == 0)
                        {
                            finish.Set();
                        }
                    }, i);
                }
                finish.WaitOne();
            }

不过注意由于使用过了匿名委托所以i的值是不确定,有可能是1或者是10,所以为了改变这种情况不能使用匿名委托,

[csharp] view plain copy

print?

  1. static private int _num = 10;
  2. static private ManualResetEvent finish = new ManualResetEvent(false);
  3. static private void ThreadWork(object state)
  4. {
  5. int i = (int)state;
  6. for (int j = 0; j < 3; j++)
  7. {
  8. Thread.Sleep(1000);
  9. Console.WriteLine("current thead {0} wait for {1} seconds.", Thread.CurrentThread.ManagedThreadId, i * 10 + j + 1);
  10. }
  11. if (Interlocked.Decrement(ref _num) == 0)
  12. finish.Set();
  13. }
        static private int _num = 10;
        static private ManualResetEvent finish = new ManualResetEvent(false);
        static private void ThreadWork(object state)
        {
            int i = (int)state;
            for (int j = 0; j < 3; j++)
            {
                Thread.Sleep(1000);
                Console.WriteLine("current thead {0} wait for {1} seconds.", Thread.CurrentThread.ManagedThreadId, i * 10 + j + 1);
            }
            if (Interlocked.Decrement(ref _num) == 0)
                finish.Set();
        }

主调函数实现代码为:

[csharp] view plain copy

print?

  1. for (int i = 0; i < _num; i++)
  2. {
  3. ThreadPool.QueueUserWorkItem(ThreadWork, i);
  4. }
  5. finish.WaitOne();
  6. finish.Close();
时间: 2024-10-14 16:40:57

C#多线程实现方法——线程池(Thread Pool)的相关文章

MySQL线程池(THREAD POOL)的原理

MySQL常用(目前线上使用)的线程调度方式是one-thread-per-connection(每连接一个线程),server为每一个连接创建一个线程来服务,连接断开后,这个线程进入thread_cache或者直接退出(取决于thread_cache设置及系统当前已经cache的线程数目),one-thread-per-connection调度的好处是实现简单,而且能够在系统没有遇到瓶颈之前保证较小的响应时间,比较适合活跃的长连接的应用场景,而在大量短连接或者高并发情况下,one-thread

Java多线程-新特性-线程池

Sun在Java5中,对Java线程的类库做了大量的扩展,其中线程池就是Java5的新特征之一,除了线程池之外,还有很多多线程相关的内容,为多线程的编程带来了极大便利.为了编写高效稳定可靠的多线程程序,线程部分的新增内容显得尤为重要. 有关Java5线程新特征的内容全部在java.util.concurrent下面,里面包含数目众多的接口和类,熟悉这部分API特征是一项艰难的学习过程.目前有关这方面的资料和书籍都少之又少,大部分介绍线程方面书籍还停留在java5之前的知识层面上. 在Java5之

Java多线程系列--“JUC线程池”01之 线程池架构

概要 前面分别介绍了"Java多线程基础"."JUC原子类"和"JUC锁".本章介绍JUC的最后一部分的内容——线程池.内容包括:线程池架构图线程池示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3509903.html 线程池架构图 线程池的架构图如下: 1. Executor 它是"执行者"接口,它是来执行任务的.准确的说,Executor提供了execute()接口来执行

Android多线程编程之线程池学习篇(一)

Android多线程编程之线程池学习篇(一) 一.前言 Android应用开发中多线程编程应用比较广泛,而应用比较多的是ThreadPoolExecutor,AsyncTask,IntentService,HandlerThread,AsyncTaskLoader等,为了更详细的分析每一种实现方式,将单独成篇分析.后续篇章中可能涉及到线程池的知识,特此本篇分析为何使用线程池,如何使用线程池以及线程池的使用原理. 二.Thread Pool基础 进程代表一个运行中的程序,一个运行中的Android

Java多线程系列--“JUC线程池”06之 Callable和Future

概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3544116.html Callable 和 Future 简介 Callable 和 Future 是比较有趣的一对组合.当我们需要获取线程的执行结果时,就需要用到它们.Callable用于产生结果,Future用于获取结果. 1. Callable Calla

多线程系列(2)线程池ThreadPool

上一篇文章我们总结了多线程最基础的知识点Thread,我们知道了如何开启一个新的异步线程去做一些事情.可是当我们要开启很多线程的时候,如果仍然使用Thread我们需要去管理每一个线程的启动,挂起和终止,显然是很麻烦的一件事情.还好.net framework为我们提供了线程池ThreadPool来帮助我们来管理这些线程,这样我们就不再需要手动地去终止这些线程.这一篇文章就让我们来学习一下线程池ThreadPool吧.关于它我想从以下几个方面进行总结. 认识线程池ThreadPool Thread

Java多线程系列--“JUC线程池”03之 线程池原理(二)

线程池示例 在分析线程池之前,先看一个简单的线程池示例. import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; public class ThreadPoolDemo1 { public static void main(String[] args) { // 创建一个可重用固定线程数的线程池 ExecutorService pool = Executors.newFixedThre

python笔记——简易线程池multiprocessing.Pool

多线程模型设计是一个比较复杂的逻辑,但是python对于多线程的处理却有种种方便的类库,不需要过多的纠结线程间的操作细节.比如multiprocessing.Pool就是其中之一. 官方给的范例也很简单. from multiprocessing import Pool def f(x): return x*x if __name__ == '__main__': pool = Pool(processes=4) # start 4 worker processes result = pool.

Java多线程设计模式(4)线程池模式

前序: Thread-Per-Message Pattern,是一种对于每个命令或请求,都分配一个线程,由这个线程执行工作.它将“委托消息的一端”和“执行消息的一端”用两个不同的线程来实现.该线程模式主要包括三个部分: 1,Request参与者(委托人),也就是消息发送端或者命令请求端 2,Host参与者,接受消息的请求,负责为每个消息分配一个工作线程. 3,Worker参与者,具体执行Request参与者的任务的线程,由Host参与者来启动. 由于常规调用一个方法后,必须等待该方法完全执行完毕