ThreadPool使用

需要定义waitcallback委托形式如

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

例如如下例子:

  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。

  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。接着等待足够长的时间来等待所有线程池里的工作完成。

  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. 如果需要获取某一个工作线程是否结束可以使用手动事件来实现。

  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;
}

主调函数实现代码为:

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

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

  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.如果需要获取多个工作线程是否结束可以通过最后一个工作线程来触发事件来实现。

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

  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,所以为了改变这种情况不能使用匿名委托,

  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();
}

主调函数实现代码为:

  1. for (int i = 0; i < _num; i++)
  2. {
  3. ThreadPool.QueueUserWorkItem(ThreadWork, i);
  4. }
  5. finish.WaitOne();
  6. finish.Close();

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

  1. 简易线程池Thread Pool

    1. 基本思路 写了个简易的线程池,基本的思路是: 有1个调度线程,负责维护WorkItem队列.管理线程(是否要增加工作线程).调度(把工作项赋给工作线程)等 线程数量随WorkItem的量动态调整 ...

  2. MySQL线程池(THREAD POOL)的原理

    MySQL常用(目前线上使用)的线程调度方式是one-thread-per-connection(每连接一个线程),server为每一个连接创建一个线程来服务,连接断开后,这个线程进入thread_c ...

  3. 线程池 (thread pool) 的类型与实现方式

    在许多应用中需要频繁的创建许多生命周期很短的线程,如果用传统方法的话就会造成大量的资源了浪费,java的设计者们考虑到了这点在java中加入了线程池这个特性,它负责管理大量的线程的创建销毁等操作. 首 ...

  4. 使用boost实现线程池thread pool | boost thread pool example

    本文首发于个人博客https://kezunlin.me/post/f241bd30/,欢迎阅读! boost thread pool example Guide boost thread pool ...

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

    概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.co ...

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

    概要 前面分别介绍了"Java多线程基础"."JUC原子类"和"JUC锁".本章介绍JUC的最后一部分的内容——线程池.内容包括:线程池架构 ...

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

    Sun在Java5中,对Java线程的类库做了大量的扩展,其中线程池就是Java5的新特征之一,除了线程池之外,还有很多多线程相关的内容,为多线程的编程带来了极大便利.为了编写高效稳定可靠的多线程程序 ...

  8. 温故知新-java多线程&深入理解线程池

    文章目录 摘要 java中的线程 java中的线程池 线程池技术 线程池的实现原理 简述 ThreadPoolExecutor是如何运行的? 线程池运行的状态和线程数量 任务执行机制 队列缓存 Wor ...

  9. Java多线程系列--“JUC线程池”02之 线程池原理(一)

    概要 在上一章"Java多线程系列--“JUC线程池”01之 线程池架构"中,我们了解了线程池的架构.线程池的实现类是ThreadPoolExecutor类.本章,我们通过分析Th ...

随机推荐

  1. licecap图片区域问题

    之前一直好用的licecap最近突然没法用了,结果发现是屏幕分辨率的文本大小的问题,因为选了特大的.发现制作成的gif图片的区域有问题.后来改回中等的,就可以了.

  2. SpringMVC(AbstractController,拦截器,注解)

    1.Controller接口及其实现类 Controller是控制器/处理器接口,只有一个方法handleRequest,用于进行请求的功能处理(功能处理方法),处理完请求后返回ModelAndVie ...

  3. HDU 3607 线段树+DP+离散化

    题意:从左往右跳箱子,每个箱子有金币数量,只能从矮处向高处跳,求最大可获得金币数,数据规模1<=n<=1e5. 显然是一个dp的问题,不难得出dp[ i ] = max(dp[j] )+v ...

  4. Vue——组件上使用v-model

    一.最近在工作过程中要实现一个搜索模糊匹配功能,考虑到组件的复用,就单独把搜索框抽出来作为一个子组件.在以往的开发中,我一般会在input框中的值变化时向父组件emit一个事件,并带上一些父组件中需要 ...

  5. Word 多级节标题设置和图表章节号自动生成

    写文章的时候,正文.图表.节标题,通过“样式”可以进行统一设置,这里我记录了几点小技巧: 1.多级标题如何设置 假设我要设置三级标题,下面以图的形式记录方式: 设置完之后,应用即可. 章节设定之后,可 ...

  6. Apache Spark 2.2.0 中文文档 - Spark Streaming 编程指南

    Spark Streaming 编程指南 概述 一个入门示例 基础概念 依赖 初始化 StreamingContext Discretized Streams (DStreams)(离散化流) Inp ...

  7. HttpServlet中service方法的源码解读

    前言     最近在看<Head First Servlet & JSP>这本书, 对servlet有了更加深入的理解.今天就来写一篇博客,谈一谈Servlet中一个重要的方法-- ...

  8. CSS——垂直居中

    vertical-align 垂直对齐 以前我们讲过让带有宽度的块级元素居中对齐,是margin: 0 auto; 以前我们还讲过让文字居中对齐,是 text-align: center; 但是我们从 ...

  9. 一张图轻松掌握 Flink on YARN 应用启动全流程(上)

    Flink 支持 Standalone 独立部署和 YARN.Kubernetes.Mesos 等集群部署模式,其中 YARN 集群部署模式在国内的应用越来越广泛.Flink 社区将推出 Flink ...

  10. Ubuntu-WPS无法输入中文

    WPS无法输入中文 原因:环境变量未正确设置 $ vi /usr/bin/wps,添加以下内容: #!/bin/bash export XMODIFIERS="@im=fcitx" ...