多线程系列(三):线程池基础

目录:

  • 为什么要使用线程池
  • 简单的线程池操作
  • 执行上下文
  • 协作式取消

一、为什么要使用线程池:线程池概念理解

备注:线程池中的线程是后台线程。

1、为什么会有线程池?

  因为创建线程和销毁线程相对来说需要消耗大量的时间和资源。 太多的线程会浪费内存。

       操作系统需要在线程间来回切换,线程过多,有损性能。

2、线程池是什么?

  线程池就是一个可持续性发展的线程集合,线程池内部维护着一个消息队列。

  当一条方法名引用追加到线程池的队列中,线程池会提取当前项,派发给线程池中空闲的线程。

3、线程池创建线程策略?

  • 如果线程池中没有线程,就创建一个线程。
  • 如果并发的请求数过多,且请求速度超出线程池处理速度,就会创建额外线程。
  • 如果线程完成任务,不会销毁,会进入空闲状态,等待下个请求的响应。
  • 如果在一定的时间内没有接收到请求,超度空闲,就会自己醒来,终止自己,释放资源。

 

二、简单的线程池操作

我们上面提到过,线程池内维护的了一个消息队列,方法引用追加到队列中,线程池中的线程从队列中取出等待执行。

[SecuritySafeCritical]
 public static bool QueueUserWorkItem(WaitCallback callBack);
[SecuritySafeCritical]
 public static bool QueueUserWorkItem(WaitCallback callBack, object state);

委托:

 [ComVisible(true)]
  public delegate void WaitCallback(object state);

所以,一个是参数为null,一个是需要传递实参的委托。要使用以上方式向队列中添加工作项,其实是将方法引用添加到队列中

1、我们定义一个符合 WaitCallback 规则的委托 一个参数且没有返回值

   public static void WorkerFun(object flag)
   {
            Console.WriteLine("【WorkerFun】 doing ........");
            for (int index = 10; index > 0; index--)
            {
                Console.WriteLine("     {0}s", index);
                Thread.Sleep(2000);
            }
      Console.WriteLine("【WorkerFun】end.");
    }

2、我们使用线程池进行异步调用

public void Run(string args)
{
    Console.WriteLine("【Main】doing......");
    if (ThreadPool.QueueUserWorkItem(WorkerFun))
    {
        Console.WriteLine("Add pool success");
    }
    Console.WriteLine("【Main】sleep 5s.");
  
Thread.Sleep(5000);
Console.WriteLine("【Main】end.");
}

运行结果:

主线程执行完毕,子线程自动关闭。所以说,线程池中的线程都是后台线程,优先级比较低。

 

二、执行上下文

1、为什么要有执行上下文 ?

线程在执行代码时,会受到上下文的影响。

上下文会从初始线程流向辅助线程,这样这整个线程使用相同的安全设置和宿主设置。

同样,辅助线程可以使用初始线程的逻辑上下文。

namespace System.Threading
    //执行上下文
  public sealed class ExecutionContext : IDisposable, ISerializable
    {
        //从当前线程捕获执行上下文 
        [SecuritySafeCritical]
        public static ExecutionContext Capture();  
        //是否取消了执行上下文的流动        
        public static bool IsFlowSuppressed(); 
        //恢复执行上下文在异步线程之间的流动        
        public static void RestoreFlow();       
        //在当前线程上的指定执行上下文中运行某个方法
        [SecurityCritical]
        public static void Run(ExecutionContext executionContext, ContextCallback callback, object state);        
        //取消执行上下文在异步线程之间的流动  
        [SecurityCritical]
        public static AsyncFlowControl SuppressFlow(); 
        //创建当前执行上下文的副本           
        [SecuritySafeCritical]
        public ExecutionContext CreateCopy(); 
        [SecuritySafeCritical]
        public void Dispose();       
        [SecurityCritical]
        public void GetObjectData(SerializationInfo info, StreamingContext context);
    }

通过执行上下文我们来控制上下文的流动。

CallContext.LogicalSetData("Name", "sc");
//默认允许上下文进行流动
ThreadPool.QueueUserWorkItem(state => Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name")));
//现在禁止流动
ExecutionContext.SuppressFlow();
ThreadPool.QueueUserWorkItem(state => Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name")));
//恢复流动
ExecutionContext.RestoreFlow();
Console.ReadKey();

运行:第一行允许流动;第二行禁止流动

Name=sc
Name=

 

三、协作式取消和超时

需要取消的模式必须显示支持取消

//通知 System.Threading.CancellationToken,告知其应被取消
public sealed class CancellationTokenSource : IDisposable

CancellationTokenSource  管理 着取消相关的状态.

所谓协作式,首先我自己要支持取消,接收信号后任务终止。

private static void Count(System.Threading.CancellationToken token, int countto)
{
    for (int count = 0; count < countto; count++)
    {
        Console.WriteLine("index:{0}", count);
        if (token.IsCancellationRequested)
        {
            Console.WriteLine("Count is cancelled  {0}",count);
            break;
        }
    }
}

 主线程中,接收协作式取消命令,子线程检测到信号后,主动停止。

public void Run(string args)
{         
    System.Threading.CancellationTokenSource cts = new CancellationTokenSource();
    //开启线程
    ThreadPool.QueueUserWorkItem(state => Count(cts.Token, 10000000));
    Console.WriteLine("Press <Enter> to cancel the operation");
    Console.ReadLine();
    cts.Cancel();
    Console.ReadLine();
}

 运行结果:主线程发出回车信号,子线程检测到信号后结束任务。

 

posted @ 2018-03-28 22:35  K战神  阅读(283)  评论(0编辑  收藏  举报