• 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

  • 相关阅读:
    Java && Eclipse使用中的问题
    Java使用的扩展
    Java的基本使用之多线程
    Java的基本使用之反射
    Java的基本使用之IO
    Java的基本使用之异常处理
    CSS中的line-height和vertical-height
    Java的基本使用之多线程
    跟进记录
    将文件从已Root Android手机中copy出来的几个cmd窗口命令
  • 原文地址:https://www.cnblogs.com/zxtceq/p/7791743.html
Copyright © 2020-2023  润新知