C#多线程学习 之 线程池[ThreadPool]

348 篇文章 0 订阅
67 篇文章 0 订阅
C#多线程学习 之 线程池[ThreadPool]

在多线程的程序中,经常会出现两种情况:

一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应
                  这一般使用ThreadPool(线程池)来解决;

另一种情况:线程平时都处于休眠状态,只是周期性地被唤醒
                  这一般使用Timer(定时器)来解决;

本篇文章单单讲线程池[ThreadPool]

ThreadPool类 MSDN帮助信息: http://msdn.microsoft.com/zh-cn/library/system.threading.threadpool.aspx#Y0

将任务添加进线程池:

ThreadPool.QueueUserWorkItem(new WaitCallback(方法名));

重载

ThreadPool.QueueUserWorkItem(new WaitCallback(方法名), 参数);

因为ThreadPool是静态类 所以不需要实例化.

 

对于线程池主要的控制有控制线程数大小:

ThreadPool.SetMaxThreads 方法

public static bool SetMaxThreads(
	int workerThreads,
	int completionPortThreads
)

参数:

workerThreads
类型: System.Int32
线程池中辅助线程的最大数目。
completionPortThreads
类型: System.Int32
线程池中异步 I/O 线程的最大数目。

例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace 多线程池试验
{
     class Program
     {
         public static void Main()
         {
             ThreadPool.SetMaxThreads(3, 3);
             for ( int i = 0; i < 50; i++)
             {
                 thr t = new thr();
                 ThreadPool.QueueUserWorkItem( new WaitCallback(t.ThreadProc), i);
             }
             Console.WriteLine( "断点测试" );
             Thread.Sleep(100000);
 
             Console.WriteLine( "运行结束" );
         }
 
         public class thr
         {
             public void ThreadProc( object i)
             {
                 Console.WriteLine( "Thread[" + i.ToString() + "]" );
                 Thread.Sleep(1000);
             }
         }
     }
}

输出结果:

image

您会发现 断点测试 在上面了, 这是什么原因呢?

原因:

1. 线程池的启动和终止不是我们程序所能控制的, 我反正是不知道的, 你如果知道的话 可以发邮件给我 henw@163.com

2. 线程池中的线程执行完之后是没有返回值的.

总之一句话, 我们不知道线程池他干了什么, 那么我们该怎么解决 任务完成问题呢?

操作系统提供了一种”信号灯”(ManualResetEvent)

ManualResetEvent 允许线程通过发信号互相通信。通常,此通信涉及一个线程在其他线程进行之前必须完成的任务。当一个线程开始一个活动(此活动必须完成后,其他线程才能开始)时,它调用 Reset 以将 ManualResetEvent 置于非终止状态,此线程可被视为控制 ManualResetEvent。调用 ManualResetEvent 上的 WaitOne 的线程将阻止,并等待信号。当控制线程完成活动时,它调用 Set 以发出等待线程可以继续进行的信号。并释放所有等待线程。一旦它被终止,ManualResetEvent 将保持终止状态(即对 WaitOne 的调用的线程将立即返回,并不阻塞),直到它被手动重置。可以通过将布尔值传递给构造函数来控制 ManualResetEvent 的初始状态,如果初始状态处于终止状态,为 true;否则为 false。

详细见MSDN: http://msdn.microsoft.com/zh-cn/library/system.threading.manualresetevent.aspx

主要使用了

eventX.WaitOne(Timeout.Infinite, true);  阻止当前线程,直到当前 WaitHandle 收到信号为止。

eventX.Set(); 将事件状态设置为终止状态,允许一个或多个等待线程继续。

修改后的程序:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace 多线程池试验
{
     class Program
     {
         public static void Main()
         {
             //新建ManualResetEvent对象并且初始化为无信号状态
             ManualResetEvent eventX = new ManualResetEvent( false );
             ThreadPool.SetMaxThreads(3, 3);
             thr t = new thr(15, eventX);
             for ( int i = 0; i < 15; i++)
             {
                 ThreadPool.QueueUserWorkItem( new WaitCallback(t.ThreadProc), i);
             }
             //等待事件的完成,即线程调用ManualResetEvent.Set()方法
             //eventX.WaitOne  阻止当前线程,直到当前 WaitHandle 收到信号为止。
             eventX.WaitOne(Timeout.Infinite, true );
             Console.WriteLine( "断点测试" );
             Thread.Sleep(10000);
             Console.WriteLine( "运行结束" );
         }
 
         public class thr
         {
             public thr( int count,ManualResetEvent mre)
             {
                 iMaxCount = count;
                 eventX = mre;
             }
 
             public static int iCount = 0;
             public static int iMaxCount = 0;
             public ManualResetEvent eventX;
             public void ThreadProc( object i)
             {
                 Console.WriteLine( "Thread[" + i.ToString() + "]" );
                 Thread.Sleep(2000);
                 //Interlocked.Increment()操作是一个原子操作,作用是:iCount++ 具体请看下面说明
                 //原子操作,就是不能被更高等级中断抢夺优先的操作。你既然提这个问题,我就说深一点。
                 //由于操作系统大部分时间处于开中断状态,
                 //所以,一个程序在执行的时候可能被优先级更高的线程中断。
                 //而有些操作是不能被中断的,不然会出现无法还原的后果,这时候,这些操作就需要原子操作。
                 //就是不能被中断的操作。
                 Interlocked.Increment( ref iCount);
                 if (iCount == iMaxCount)
                 {
                     Console.WriteLine( "发出结束信号!" );
                     //将事件状态设置为终止状态,允许一个或多个等待线程继续。
                     eventX.Set();
                 }
             }
         }
     }
}

输出结果:

image

顺序正常了.

程序源码: 多线程池试验.zip

欢迎大家一起探讨!

分类: .Net
6
1
(请您对文章做出评价)
« 上一篇: 电脑方面的技巧
» 下一篇: C# 配置文件读取与修改
posted @ 2012-01-06 16:43 hen 阅读( 25534) 评论( 7) 编辑 收藏
  
#1楼 2012-01-06 17:53 红涛  
  
#2楼 2012-01-06 23:14 L.Qiu  
不错,要理解得更深刻一些,看来还需要一些操作系统中断方面的知识
  
#3楼 2013-08-01 21:56 weblogical  
博主, http://q.cnblogs.com/q/53015/ 这个问题 用线程池怎么实现呢?
  
#4楼 2014-09-19 11:13 逢雨不出门  
请教,使用你这种方法之后,增长了很多内存,该如何清理掉这些内存呢
  
#5楼 2015-01-13 10:48 洗刷界的无头程序员  
使用了随机睡眠时间长度(模拟方法运行时间变化)后,会出现未完成就退出了。这改怎么办呢。
  
#6楼 [ 楼主] 2015-01-16 21:29 hen  
@Arvin Li
有个方法可以等待所有线程运行结束之后再执行下面的方法
https://i-blog.csdnimg.cn/blog_migrate/ec6a06a81faebcd6c3e5941fcbf41a4a.jpeg
  
#7楼 3298818 2015/11/4 13:40:43 2015-11-04 13:40 ^清小怨  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值