C#多线程实现方法——线程池(Thread Pool)
ThreadPool使用
需要定义waitcallback委托形式如
- public delegate void WaitCallback(object state);
public delegate void WaitCallback(object state);
例如如下例子:
- 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;
- }
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。
- 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
- ) ;
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。接着等待足够长的时间来等待所有线程池里的工作完成。
- 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
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. 如果需要获取某一个工作线程是否结束可以使用手动事件来实现。
- 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;
- }
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;
}
主调函数实现代码为:
- ThreadPool.QueueUserWorkItem(ThreadWorker);
- finish.WaitOne();
- finish.Close();
ThreadPool.QueueUserWorkItem(ThreadWorker);
finish.WaitOne();
finish.Close();
或者使用匿名委托函数加using关键字保证了事件的释放
- 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();
- }
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.如果需要获取多个工作线程是否结束可以通过最后一个工作线程来触发事件来实现。
如果使用前面的方法给每一个工作线程分配一个事件,然后等待所有事件给触发,是非常低效的,可以使用如下方法
- 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();
- }
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,所以为了改变这种情况不能使用匿名委托,
- 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();
- }
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();
}
主调函数实现代码为:
- for (int i = 0; i < _num; i++)
- {
- ThreadPool.QueueUserWorkItem(ThreadWork, i);
- }
- finish.WaitOne();
- finish.Close();
C#多线程实现方法——线程池(Thread Pool)的更多相关文章
- 简易线程池Thread Pool
1. 基本思路 写了个简易的线程池,基本的思路是: 有1个调度线程,负责维护WorkItem队列.管理线程(是否要增加工作线程).调度(把工作项赋给工作线程)等 线程数量随WorkItem的量动态调整 ...
- MySQL线程池(THREAD POOL)的原理
MySQL常用(目前线上使用)的线程调度方式是one-thread-per-connection(每连接一个线程),server为每一个连接创建一个线程来服务,连接断开后,这个线程进入thread_c ...
- 线程池 (thread pool) 的类型与实现方式
在许多应用中需要频繁的创建许多生命周期很短的线程,如果用传统方法的话就会造成大量的资源了浪费,java的设计者们考虑到了这点在java中加入了线程池这个特性,它负责管理大量的线程的创建销毁等操作. 首 ...
- 使用boost实现线程池thread pool | boost thread pool example
本文首发于个人博客https://kezunlin.me/post/f241bd30/,欢迎阅读! boost thread pool example Guide boost thread pool ...
- Java多线程系列--“JUC线程池”06之 Callable和Future
概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.co ...
- Java多线程系列--“JUC线程池”01之 线程池架构
概要 前面分别介绍了"Java多线程基础"."JUC原子类"和"JUC锁".本章介绍JUC的最后一部分的内容——线程池.内容包括:线程池架构 ...
- Java多线程-新特性-线程池
Sun在Java5中,对Java线程的类库做了大量的扩展,其中线程池就是Java5的新特征之一,除了线程池之外,还有很多多线程相关的内容,为多线程的编程带来了极大便利.为了编写高效稳定可靠的多线程程序 ...
- 温故知新-java多线程&深入理解线程池
文章目录 摘要 java中的线程 java中的线程池 线程池技术 线程池的实现原理 简述 ThreadPoolExecutor是如何运行的? 线程池运行的状态和线程数量 任务执行机制 队列缓存 Wor ...
- Java多线程系列--“JUC线程池”02之 线程池原理(一)
概要 在上一章"Java多线程系列--“JUC线程池”01之 线程池架构"中,我们了解了线程池的架构.线程池的实现类是ThreadPoolExecutor类.本章,我们通过分析Th ...
随机推荐
- Spring Boot + kkFileView-2.1.2 实现文档在线预览
1. 下载kkFileview:https://gitee.com/kekingcn/file-online-preview/releases 2. 启动服务 进入 bin 目录,双击 startup ...
- Python+Django+ansible playbook自动化运维项目实战✍✍✍
Python+Django+ansible playbook自动化运维项目实战 整个课程都看完了,这个课程的分享可以往下看,下面有链接,之前做java开发也做了一些年头,也分享下自己看这个视频的感受 ...
- websocket接口测试
1.先在jmeter的插件管理器安装webSocket的插件,WebSocket 常规选项解释如下: ip:测试服务器域名 Streaming Connection:请求之后是否保持连接,勾选之后在同 ...
- iOS开发系列-Category
Category Category是OC中特有的语法.Category的作用 * 可以在不修改原来类的基础上,为这个类扩充一些方法 * 一个庞大的类可以分为多个模块开发 * 一个庞大的类可以由多个人来 ...
- final修饰和StringBuffer的几个案例(拼接,反转,对称操作)
final关键字修饰时如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改:如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象,但引用变量不能变,引用变量所指向的对象中的内容还 ...
- C# 创建DataTable并添加行和列
DataTable dt=new DataTable dt.Columns.Add("numview", typeof(Int32)); dt.Columns.Add(" ...
- foreach循环的简单写法
简单的foreach循环写法: pickedItems.ForEach(item => { this.List.Remove(item); }); //注意,List 必须和pickedItem ...
- 2019 年百度之星·程序设计大赛 - 初赛一 C. Mindis 离散化+dijkstra
题目传送门 题意:中文题面 思路: 先将所有题目给出的点离散化一下,得到一张n*m的网格,n和m最大都是400,所以我们只需要枚举每个加强的区域,将属于这个区域的边处理一下(所有横着的和竖着的边,暴力 ...
- canvas像素的操作
###在canvas中的像素操作 到目前为止,我们尚未深入了解Canvas画布真实像素的原理,事实上, 你可以直接通过ImageData对象操纵像素数据,直接读取或将数据数组写入该对象中 ###得到场 ...
- JavaScript 点击事件的三种写法
嵌入式 <button οnclick='alert("hello")'>点击按钮</button> 脚本模型 btn.onclick=function() ...