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

输出结果:

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

原因:

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

输出结果:

顺序正常了.

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

http://www.cnblogs.com/henw/archive/2012/01/06/2314870.html的更多相关文章

  1. http://www.cnblogs.com/zhaoyang/archive/2012/01/07/2315436.html

    http://www.cnblogs.com/zhaoyang/archive/2012/01/07/2315436.html

  2. http://www.cnblogs.com/TankXiao/archive/2012/02/06/2337728.html

    http://www.cnblogs.com/TankXiao/archive/2012/02/06/2337728.html

  3. java解析xml汇总(转自倾城幻影-Java解析xml汇总,链接:http://www.cnblogs.com/jiugehuanying/archive/2012/01/12/2320058.html)

    [引言] 目前在Java中用于解析XML的技术很多,主流的有DOM.SAX.JDOM.DOM4j,下文主要介绍这4种解析XML文档技术的使用.优缺点及性能测试. [一.基础知识--扫盲] sax.do ...

  4. OpenGL3D图形、旋转、纹理、键盘移动、光照、滤波、透明(完整) 转自http://www.cnblogs.com/tiandsp/archive/2012/01/23/2329049.html

    #include <windows.h> // Windows的头文件 #include <stdio.h> #include <gl\gl.h> // OpenG ...

  5. ESB简介及选型(转) http://www.cnblogs.com/skyme/archive/2012/08/06/2623414.html

    什么是ESB 企业服务总线(Enterprise Service Bus,ESB)的概念是从面向服务体系架构(Service Oriented Architecture, SOA)发展而来的.SOA描 ...

  6. Centos7 systemctl和防火墙firewalld命令(参考https://www.cnblogs.com/marso/archive/2018/01/06/8214927.html)

    一.防火墙的开启.关闭.禁用命令 (1)设置开机启用防火墙:systemctl enable firewalld.service (2)设置开机禁用防火墙:systemctl disable fire ...

  7. http://www.cnblogs.com/stephen-liu74/archive/2012/08/01/2561557.html

    http://www.cnblogs.com/stephen-liu74/archive/2012/08/01/2561557.html

  8. http://www.cnblogs.com/Lawson/archive/2012/09/03/2669122.html

    http://www.cnblogs.com/Lawson/archive/2012/09/03/2669122.html

  9. http://www.cnblogs.com/Matrix54/archive/2012/05/03/2481260.html

    http://www.cnblogs.com/Matrix54/archive/2012/05/03/2481260.html

随机推荐

  1. libGDX 模块概览

    本文章翻译自libGDX官方wiki,.转载请注明出处:http://blog.csdn.net/kent_todo/article/details/37940595 libGDX官方网址:http: ...

  2. CSS3 实现背景透明,文字不透明,兼容所有浏览器

    <!DOCTYPE html><html><head><meta charset="utf-8"><title>opac ...

  3. 18- php Redis扩展编译

    一:php扩展编译Redis :wget http://pecl.php.net/get/redis-2.2.5.tgz :tar -zxvf redis-.tgz :cd redis- :/usr/ ...

  4. 高特权级代码段转向低特权级代码段(利用 ret(retf) 指令实现 jmp from ring0 to ring3)

    [0]写在前面 0.1)本代码旨在演示 从 ring0 转移到 ring3(即,从高特权级 转移到 低特权级) 0.2)本文 只对 与 门相关的 代码进行简要注释,言简意赅: 0.3)文末的个人总结是 ...

  5. 抽钻石vs中奖门 概率问题

    在概率问题中,假设跟着日常经验与感觉走.常常会得到错误的答案.以下"抽钻石"的故事非常可以说明这一点. 题目一:某天电视台举办了这种一个游戏节目.主持人首先拿出三个盒子.已知这三个 ...

  6. 【转】安卓逆向(一)--Smali基础

    转载自吾爱破解安卓逆向入门教程 APK的组成 文件夹 作用 asset文件夹 资源目录1:asset和res都是资源目录但有所区别,见下面说明 lib文件夹 so库存放位置,一般由NDK编译得到,常见 ...

  7. Yii的权限管理rbac

    1.首先我们要在配置文件的组件(component)里面配置一下 Rbac 在对应项目下的config/main.php或者config/main-local.php下添加 'authManager' ...

  8. Java&amp;Xml教程(十)XML作为属性文件使用

    我们一般会将Java应用的配置參数保存在属性文件里.Java应用的属性文件能够是一个正常的基于key-value对,以properties为扩展名的文件.也能够是XML文件. 在本案例中.將会向大家介 ...

  9. python 基础 8.2 编译正则对象

    #/usr/bin/python #coding=utf-8 #@Time   :2017/11/14 9:55 #@Auther :liuzhenchuan #@File   :编译正则对象.py ...

  10. python 基础 3.2 文件 for 练习

    #/usr/bin/python #coding=utf-8 #@Time   :2017/11/1 22:19 #@Auther :liuzhenchuan #@File   :1030-1031练 ...