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. Neo4j模糊查询及分页查询

    Neo4j模糊查询:采用正则方式: MATCH (n:House) where n.Name =~ '李.*' RETURN n 分页: 使用skip 及 limit MATCH (n:House) ...

  2. Error resolving template,template might not exist or might not be accessible by any of the configured Template Resolvers

    template might not exist or might not be accessible by any of the configured Template Resolvers at o ...

  3. springboot中参数校验

    <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring- ...

  4. iOS 工程实现native 跳转指定的Flutter 页面

    概要 在前一篇文章中我们提到,iOS跳转到Flutter工程指定页面时(多个),Flutter只有单例,设置setInitialRouter 无效,如下 let flutterViewControll ...

  5. 2019-7-29-C#-在基类定义好方法让子类继承接口就能实现

    title author date CreateTime categories C# 在基类定义好方法让子类继承接口就能实现 lindexi 2019-07-29 09:57:49 +0800 201 ...

  6. php 查看linux服务器的磁盘使用情况

  7. python库之lightgbm

    一.安装 https://blog.csdn.net/qq_40317897/article/details/81021958 参考文献: [1].LightGBM中文文档 https://light ...

  8. sql中取出字符串中数字

    select substring(reverse('0->星光'),PATINDEX('%[0-9]%',reverse('0->星光')),1)

  9. python读文件判断是否已到EOF

    python读文件判断是否已到EOF,也即结尾,一般其它语言都是以EOF直接来判断的,比如 if ( fp.read(chunk_size) == EOF), 但python到结尾后是返回空字符串的, ...

  10. thinkphp 运算符

    我们可以对模板输出使用运算符,包括对“+”“ –” “*” “/”和“%”的支持. 大理石平台厂家 例如: 运算符 使用示例 + {$a+$b} - {$a-$b} * {$a*$b} / {$a/$ ...