一、CLR线程池

1、进程和CLR的关系
一个进程可以只包含一个CLR,也可以包含多个CLR
2、CLR和AppDomain的关系
一个CLR可以包含多个AppDomain
3、CLR和线程池的关系
一个CLR只包含一个线程池
所以得出一个CLR下的多个AppDomain共享一个线程池和一个进程下的多个CLR拥有多个线程池的结论.注:多个线程池间的线程池相互不产生影响.

4、CLR和线程池和操作请求队列的关系
(1)、CLR第一次初始化时,线程池并没有线程,当应用程序调用异步代码执行一个方法时,会将该请求记录项加入到操作请求队列中,线程池的代码从这个队列中获取记录项,并派发给线程池线程,接着
线程池会创建线程,当然这里会有性能开销,但是当该线程执行完毕之后,线程池会回收这个线程,这里注意:线程池不会直接销毁这个线程,而是让它处于闲置状态.这样就不会产生额外的性能开销.
但是如果该线程如果长时间处于闲置状态,那么线程池会销毁它,关于这个时间的计算很复杂,各个CLR对它的定义各不相同.
(2)、当应用程序向线程池发起了多个请求,线程池会尝试用一个线程来处理你所有的请求,但是如果这个线程处理压力过大,那么它会开启一个新的线程来给它分担压力.以此类推.
(3)、线程池之包含了少量线程,因为如果线程太多,会增加性能开销,当然如果你升级了你电脑的cpu,线程池则会创建更多的线程.这个过程线程池会自动的去读取你得cpu核数信息,自动的去分配合适的线程数
合理地分配CPU资源.当应用程序的压力减轻,那么它会销毁不用的线程.

(4)、代码演示

     static void Main(string[] args)
{
Console.WriteLine("主线程开始执行,调用一个带参数的线程池子线程");
//主线程调用ThreadPool.QueueUserWorkItem方法向线程池的操作队列添加一个记录项
//线程池会遍历这个操作队列的所有记录项,然后将记录项中派发给一个线程池线程
//接着线程池的线程就开始执行ExecuteOtherWork方法(同时接受了主线程传递给它的参数)
ThreadPool.QueueUserWorkItem(ExecuteOtherWork,);
Console.WriteLine("主线程继续执行");
Console.WriteLine("两个线程全部执行完毕");
Console.Read();//这行代码必须加,因为线程池是后台线程,当进程关闭,该进程所有的后台线程都会被关闭,不管是否执行完毕.
} /// <summary>
/// 线程池子线程调用的方法
/// </summary>
/// <param name="state"></param>
static void ExecuteOtherWork(object state)
{
Console.WriteLine("线程池子线程开始执行,主线程传递给它的参数是:{0}", state);
Console.WriteLine("线程池子线程执行完毕");
}

注:这里的输出顺序不确定,因为在多核机器下,可能线程调度器会同时执行主线程和子线程.

四、关于线程池线程的执行上下文

(1)、什么是执行上下文

执行上下文是初始线程的环境描述的数据结构,该结构包含以下东西:

i、安全设置(压缩栈、Thread的Principal属性( 获取或设置线程的当前负责人(对基于角色的安全性而言))和Windows身份)

ii、宿主设置 详情参见HostExecutionContext、HostExecutionContextManager类,通过该类可以设置宿主上下文的状态、以及创建当前宿主上下文的副本.代码,并设置子线程的上下文为主线程的上下文:

      static void Main(string[] args)
{
Console.WriteLine("主线程开始执行,调用一个带参数的线程池子线程");
var mainThreadContext = new HostExecutionContext("");
mainThreadContext=mainThreadContext.CreateCopy();
var thread = new Thread(ExecuteOtherWork);
thread.Start(mainThreadContext);
Console.Read();
} /// <summary>
/// 线程池子线程调用的方法
/// </summary>
/// <param name="state"></param>
static void ExecuteOtherWork(object state)
{
var manager = new HostExecutionContextManager();
manager.SetHostExecutionContext(state as HostExecutionContext);
Console.WriteLine("子线程执行完毕");
}

凑合着看,暂时还没有发现这么做的实际意义.可能只有微软知道。哈哈!CLR默认造成初始线程的上下文流向任何子线程。

注:当初始线程创建多个辅助线程时,线程池默认辅助初始线程的上下文,并复制给所有的辅助线程.关于上下文复制的这种机制,很清楚,肯定会造成性能上的开销,每开启一个新的线程就会复制原有线程的上下文给新的线程.

但是考虑到性能问题,MS提供了ExecutionContext取消上下文复制的这种机制.

        private static string shareKey = "线程之间共享的数据槽值键";
static void Main(string[] args)
{ Console.WriteLine("主线程开始执行,调用一个带参数的线程池子线程");
CallContext.LogicalSetData(shareKey, "");
ExecutionContext.SuppressFlow();
var thread = new Thread(ExecuteOtherWork);
thread.Start();
Console.Read();
} /// <summary>
/// 线程池子线程调用的方法
/// </summary>
/// <param name="state"></param>
static void ExecuteOtherWork(object state)
{
Console.WriteLine("线程之间共享的数据槽值:{0}", CallContext.LogicalGetData(shareKey));
Console.WriteLine("子线程执行完毕");
}

关于CallContext.LogicalSetData参考下面的例子

iii、逻辑调用上下文数据结构CallContext类,关于它的用法,如下:

        private static string notShareContextKey = "线程内唯一的对象,无法共享到其他线程";

        private static string shareContextKey = "线程之间共享的对象,可以传播到其他线程";

        static void Main(string[] args)
{
Console.WriteLine("主线程开始执行,调用一个带参数的线程池子线程");
CallContext.SetData(notShareContextKey, "");
CallContext.LogicalSetData(shareContextKey, "");
var thread = new Thread(ExecuteOtherWork);
thread.Start();
Console.WriteLine("看看主线程能不能通过CallContext.SetData方法拿到这个数据:{0}", CallContext.GetData(notShareContextKey) ??"没有拿到");
Console.WriteLine("看看主线程能不能通过CallContext.LogicalSetData方法拿到主线程的逻辑上下文对象里面设置的数据:{0}", CallContext.LogicalGetData(shareContextKey) ?? "没有拿到");
Console.Read();
} /// <summary>
/// 线程池子线程调用的方法
/// </summary>
/// <param name="state"></param>
static void ExecuteOtherWork(object state)
{
var obj=CallContext.GetData("线程内唯一的对象,无法共享到其他线程");
Console.WriteLine("看看子线程能不能通过CallContext.SetData方法拿到主线程的逻辑上下文对象里面设置的数据:{0}", CallContext.GetData(notShareContextKey) ?? "没有拿到");
Console.WriteLine("看看子线程能不能通过CallContext.LogicalSetData方法拿到主线程的逻辑上下文对象里面设置的数据:{0}", CallContext.LogicalGetData(shareContextKey) ?? "没有拿到");
Console.WriteLine("");
Console.WriteLine("子线程执行完毕");
}

CallContext.SetData设置的数据线程内唯一,不能跨线程调用,但是CallContext.LogicalSetData可以跨线程调用.后者类似于HttpContext的Session机制,用于保存用户信息,不受多线程的影响,如果你希望你的数据随着线程的消失而消失可以使用前者来做,其实HttpContext上下文的本质就是使用CallContext,我推测的,没有检验,但是效果是一样的,本身用户的请求就相当于一个线程.所以,可以通过对这两者的理解,可以封装一个对象,该对象维持一个应用程序上下文,同时能满足Web应用,可其他基于线程池的应用.即使在多线程环境下,也能很好的维护一些应用全局共享的关键数据.具体请参考大内老A的文章http://www.cnblogs.com/artech/archive/2010/02/25/1673792.html,写的很好.关于两个方法在代码层面的区别.这里我就不演示了.

C# 多线程学习系列三之CLR线程池系列之ThreadPool的更多相关文章

  1. Java多线程高并发学习笔记(三)——深入理解线程池

    线程池最核心的一个类:ThreadPoolExecutor. 看一下该类的构造器: public ThreadPoolExecutor(int paramInt1, int paramInt2, lo ...

  2. 浅谈线程池(上):线程池的作用及CLR线程池

    原文地址:http://blog.zhaojie.me/2009/07/thread-pool-1-the-goal-and-the-clr-thread-pool.html 线程池是一个重要的概念. ...

  3. Java多线程学习(三)volatile关键字

    转载请备注地址:https://blog.csdn.net/qq_34337272/article/details/79680693 系列文章传送门: Java多线程学习(一)Java多线程入门 Ja ...

  4. 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分

    这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...

  5. JavaSE学习笔记(13)---线程池、Lambda表达式

    JavaSE学习笔记(13)---线程池.Lambda表达式 1.等待唤醒机制 线程间通信 概念:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同. 比如:线程A用来生成包子的,线程B用 ...

  6. Android(java)学习笔记267:Android线程池形态

    1. 线程池简介  多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力.     假设一个服务器完成一项任务所需时间为:T1 创建线程时间, ...

  7. 线程机制、CLR线程池以及应用程序域

    最近在总结多线程.CLR线程池以及TPL编程实践,重读一遍CLR via C#,比刚上班的时候收获还是很大的.还得要多读书,读好书,同时要多总结,多实践,把技术研究透,使用好. 话不多说,直接上博文吧 ...

  8. Android(java)学习笔记211:Android线程池形态

    1. 线程池简介  多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力.     假设一个服务器完成一项任务所需时间为:T1 创建线程时间, ...

  9. 并发编程学习笔记(14)----ThreadPoolExecutor(线程池)的使用及原理

    1. 概述 1.1 什么是线程池 与jdbc连接池类似,在创建线程池或销毁线程时,会消耗大量的系统资源,因此在java中提出了线程池的概念,预先创建好固定数量的线程,当有任务需要线程去执行时,不用再去 ...

随机推荐

  1. c# 数据表DataTable给devexpress的gridControl提供数据源

    C# DataTable 详解 参考:https://www.cnblogs.com/Sandon/p/5175829.html http://blog.csdn.net/singgel/articl ...

  2. pageshow和pagehide事件

    Firefox和opera有一个特性,往返缓存:可以在用户使用浏览器的后退和前进按钮时加快页面的转换速度,这个缓存不仅保存了页面的数据,还有DOM和JavaScript的状态. 为了更形象的说明bfc ...

  3. js中对象继承的冒充方法

    function Parent(name){ this.name = name; this.sayName = function(){ console.log(this.name); } } func ...

  4. Vue、 React比较

    关键词:MVVM(Model-View-VIewModel)数据模型双向绑定.视图的数据变化会同时修改数据资源,数据资源的变化也会立刻反应到视图View上. 一.vue.js vue是一套构建用户界面 ...

  5. 学以致用十三-----Centos7.2+python3+YouCompleteMe成功历程

    历经几天的摸索,趟过几趟坑之后,终于完成YouCompleteMe的安装配置. 今天同样是个不能忘记的日子,国耻日,勿忘国耻.(9.18) 服务器安装好,基本配置配置好后,开始安装. ======== ...

  6. mysql delete from table 失败

    SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'; TRUNCATE TABLE ...

  7. 笔记 Bioinformatics Algorithms Chapter2

    Chapter2 WHICH DNA PATTERNS PLAY THE ROLE OF MOLECULAR CLOCKS 寻找模序 一. 转录因子会结合基因上游的特定序列,调控基因的转录表达,但是在 ...

  8. CSS Transform Style

    As CSS3 developing quickly, the transform style can be written conviently. I find that it is an inte ...

  9. 让页面整体变灰css设置

    上次看到某人去世了,百度就把相应介绍某人的信息页面全部灰掉,于是寻找到了种简单的方法,只需设置html html { filter: grayscale(100%); -webkit-filter: ...

  10. The writing on the wall

              题意:一个n*m的方格矩阵,有的格子被涂成了黑色,问该矩阵中有多少个子矩阵,子矩阵不包含黑色格子; 思路:对于一个长为L, 高为H的无黑点矩阵中包含的高为H的子矩阵个数为L+(L- ...