一、线程开销

操作系统创建线程是有代价的,其主要开销在下面列举出来了。

内存开销

  1. 线程内核对象

    拥有线程描述属性与线程上下文,线程上下文占用的内存空间为 x86 架构 占用 700 字节、x64 架构 1240 字节 、ARM 架构 350 字节。

  2. 线程环境块(TEB)

    TEB 消耗一个内存页,占用 4KB内存。

  3. 用户模式栈。

    用户模式栈存储传递给方法的局部变量与实参,并且还存储有一个地址用于当前方法返回的时候,线程应该从哪个地方继续执行。默认 Windows 分配保留 1MB 内存。

  4. 内核模式栈。

    32 位 Windows 占用 12 KB,64 位 Windows 占用 24 KB。

  5. DLL 线程连接与线程分离通知。

    这种策略只有 Windows 才会存在,当创建线程时, Windows 会调用进程所有非托管 DLL 的 DllMain 方法,并未其传递 DLL_THREAD_ATTACH 标志,线程终止时传递 DLL_THREAD_DETACH 标志。

线程上下文切换与 CPU 之间的关系

Windows 在任何时刻都只会将 1 个线程分配给 1 个 CPU ,该线程享有一个时间片的运行时间。时间片到期之后,Windows 会将上下文切换到另外一个线程,动作如下:

  1. 将 CPU 寄存器值存储在当前正在运行的线程的内核对象内部的上下文结构之中。
  2. 从先有线程集合选取一个线程供调度,如果该线程属于另一个进程,还得切换 CPU 能够操作的虚拟地址空间。
  3. 将上下文结构中的值加载到 CPU 寄存器之中。

以上操作做完之后,Windows 等待这个线程时间片到期,执行下次切换,每次切换的时间开销大概为 30 毫秒。

如果一个线程时间片结束之后,下一个调度的线程还是之前的线程则不会产生线程上下文切换。

所以在理想状态下,每个系统最佳的线程数应该与其核心数相同,(如果是 4 核 8 线程则最优应该为 8 个)因为这样上下文切换出现的情况就会少很多。

最重要的是,Windows 系统上大部分程序线程都处于空闲状态,但是线程占用的内存空间是事实存在的。

三、使用专用线程执行计算限制的异步操作

一般来说不推荐使用 Thread 手动创建线程,而应该使用线程池,不过在有以下需求时,可以手动创建线程。

  1. 需要设定更高的线程优先级的时候。
  2. 需要将线程设置为前台线程。
  3. 某些长耗时的专用线程。
  4. 该线程可能会通过 Thread 的 Abort 方法终止自身。

在调用过程中,如果使用了 Thread.Join() 方法那么就会造成调用线程阻塞当前代码,直到创建的线程被终止。

四、为什么要使用线程

  1. 针对于客户端程序而言,多线程可以增强响应性,不会因为耗时操作阻塞 UI 线程造成用户体验卡顿。
  2. 针对于服务器程序而言,可以并发地处理用户请求,充分利用多核 CPU 的优势。

作者的观点是,计算机的 CPU 使用率应该保持 100% 的使用率才不算是浪费计算资源。

五、线程调度与优先级

抢占式系统通过优先级来判定线程在什么时候调度多少时间,每个线程都分配了从 0 到 31 的优先级,系统为 CPU 分配线程时,首先检查 31 的线程,并以轮询的方式调度他们(优先级都为 31)。

如果高优先级的线程一直处于调度状态,那么操作系统不会将 CPU 分配给低优先级的线程,这样就会造成 线程饥饿

较高的优先级线程总会抢占低优先级线程,即便该线程的时间片没有用完。

CPU 会创建一个优先级为 0 的 零页线程 ,该线程是系统唯一一个优先级为 0 的线程,只有在 CPU 空闲的时候会执行他,用于清理 RAM 中所有的空闲内存页。

【注意】

进程优先级类 + 线程优先级构成了一个基础优先级,Windows 还有一个动态优先级用于防止产生线程饥饿,会动态调成线程的优先级状态。

但是动态优先级只会针对基础优先级在 0 ~ 15 的线程应用,16 ~ 31 不受这个管控。

Windows 通过两个抽象层用于表示进程优先级类和线程优先级,单一般 C# 用户代码中能够控制的只有线程优先级,他们分别是:Lowest、BelowNormal、Normal、AboveNormal、Highest。

六、前台线程与后台线程

在 CLR 中线程只有两种状态,前台线程和后台线程,而且当所有前台线程被终止之后,CLR 会强行关闭所有后台线程,并退出程序。

线程在运行的生命周期当中可以变更其状态,但主线程默认为前台线程,使用 Thread 类型创建的线程默认也是前台线程。只有线程池的线程默认为后台线程,进入托管执行的本机代码创建的任何线程也会标记为后台线程。

《CLR Via C#》读书笔记:26.线程基础的更多相关文章

  1. CLR via C# 读书笔记-26.线程基础

    前言 这俩个月没怎么写文章做记录分享,一直在忙项目上线的事情,但是学习这件事情,停下来就感觉难受,clr线程这章也是反复看了好多遍,书读百遍其义自见,今天我们来聊下线程基础 1.进程是什么,以及线程起 ...

  2. 《CLR via C#》读书笔记 之 线程基础

    第二十五章 线程基础 2014-06-28 25.1 Windows为什么要支持线程 25.2 线程开销 25.3 停止疯狂 25.6 CLR线程和Windows线程 25.7 使用专用线程执行异步的 ...

  3. [Clr via C#读书笔记]Cp4类型基础

    Cp4类型基础 Object类型 Object是所有类型的基类,有Equals,GetHashCode,ToString,GetType四个公共方法,其中GetHashCode,ToString可以o ...

  4. 《Windows核心编程》读书笔记.Chapter06线程基础

    原文链接在印象笔记(效果也好的多):https://app.yinxiang.com/l/AAQlNLnxTPRMAppVr5W0upchipQDDC_FHlU 概要: 现成也有两个组成部分: 现成的 ...

  5. CLR Via CSharp读书笔记(26) - 计算限制的异步操作

    执行上下文: 执行上下文包括安全设置(压缩栈.Thread的Principal属性和Windows身份),宿主设置(System.Threading.HostExecutionContextManag ...

  6. (CLR via C#学习笔记)异步操作 - 线程池

    一 线程池基础 1.线程池维护了一个操作请求队列,将请求的操作追加到线程池队列中,线程池的代码从队列中提取操作项,派发给线程池中的线程; 2.CLR初始化时,线程池中是没有线程的,当有操作派发给线程池 ...

  7. CLR via C# 读书笔记-21.托管堆和垃圾回收

    前言 近段时间工作需要用到了这块知识,遂加急补了一下基础,CLR中这一章节反复看了好多遍,得知一二,便记录下来,给自己做一个学习记录,也希望不对地方能够得到补充指点. 1,.托管代码和非托管代码的区别 ...

  8. Java并发读书笔记:线程安全与互斥同步

    目录 导致线程不安全的原因 什么是线程安全 不可变 绝对线程安全 相对线程安全 线程兼容 线程对立 互斥同步实现线程安全 synchronized内置锁 锁即对象 是否要释放锁 实现原理 啥是重进入? ...

  9. Clr Via C#读书笔记---I/O限制的异步操作

    widows如何执行I/O操作      构造调用一个FileStream对象打开一个磁盘文件-----FileStream.Read方法从文件中读取数据(此时线程从托管代码转为本地/用户模式代码)- ...

随机推荐

  1. 实用的JavaScript手册

    实用的JavaScript手册,收藏了,需要的时候可以翻阅 包含了 什么是JavaScript: JavaScript基础知识: JavaScript内置对象 JavaScript数据类型的操作方法 ...

  2. WCF系列_WCF常用绑定选择

    一.五种常用绑定常用绑定的传输协议以及编码格式 名称 传输协议 编码格式 互操作性 BasicHttpBinding HTTP/HTTPS Text,MTOM Yes NetTcpBinding TC ...

  3. 真机测试没有问题,but上线后安装在手机上crash。也有无法打包的情况。

    图片格式不对,把16位or p3图片改为8位sRGB图片  9.0以前不支持 解决步骤: a.找到导出项目的ipa文件修改后缀名.ipa为.zip后直接解压该文件: b.找到出问题的图片,直接把该图片 ...

  4. Unity3D 在Update中不要过多地修改Transform 信息

    前文说到碰撞检测时候,不要在Update内部尝试移动GameObject 来检查碰撞检测,这样是徒劳无功.但是 说到 因为你移动的过程中其实并没有将实际的移动位置更新到物理引擎,只是做了个缓存而已, ...

  5. Git的安装和使用

    在CentOS 6.x/7.x上安装git及最新版 方式一.yum安装 # yum install git 通过yum方式安装,版本比较旧,CentOS6.5上安装好是1.7.1版.如果想安装最新版或 ...

  6. Django之发送邮件

    Django的发送邮件是基于django的一个组件进行操作的,EmailMessage 基本使用方法: def send_html_mail(subject, html_content, from_a ...

  7. UTF-8的BOM含义

    BOM的介绍 在github上写md文件的时候,发现生成自己blog时,报出一个错误是让使用UTF-8编码,然后在Notepad++上把文件转成UTF-8时,发现菜单中有"UTF-8无BOM ...

  8. Cookie的使用(14)

    一:cookie的简要介绍: (1)什么是cookie a.cookie是一种客户端的状态管理技术b.当浏览器向服务器发送请求的时候,服务器会将少量的数据以set-cookie消息头的方式发送给浏览器 ...

  9. Fragment+Viewpaager

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...

  10. 注册MongoDB为系统服务(二)

    注册MongoDB为系统服务(二)http://blog.csdn.net/qq_35685189/article/details/52304245