C# 多线程学习系列一
一、Windows线程的由来 关于操作系统的一些知识
(1)、单个"工作线程"的问题
早期的Windows没有线程的概念,整个系统只有一个"工作线程",上面同时跑着操作系统代码和应用程序代码.这种方式最大的缺点就是,一个应用程序运行时会霸占整台机器(应为只有一个工作线程),且当它发生死循环时,会造成PC停止工作.如果此时重启,更shit的是,所有的应用程序都会停止,且丢失数据.
(2)、Windows进程
i、什么是Windows进程,以及它解决的问题
MS为了解决单个"工作线程"的问题,设计了新的内核,该内核实现了Windows进程的功能,每个Windows进程(应用程序要使用的资源集合)运行一个应用程序,如下图:

一个Chrome浏览器进程包含了很多子进程(子进程可以共享父进程的资源),后面包含了正在使用的资源集合,包括CPU、内存等.每个进程都有一个虚拟空间地址(PID).
当一个应用程序应为代码故障发生卡死等问题,并不会影响其他的应用程序的运行,只需要打开任务管理器,将该进程关闭即可.其他应用程序的数据也不会丢失,因为它们是彼此独立的进程.
ii、Window进程的安全性
在Windows中,进程之间不能相互访问(不包括父子进程),单个进程也无法访问Windows内核.
iii、关于CPU的问题
虽然Windows进程很好的解决了单个"工作线程"的问题,Windows不会发生一个应用程序崩溃,所有应用程序全都停止且所有运行着的应用程序的数据丢失的情况。但是如果PC只有一个CPU,当CPU本身发生死循环等问题,还是会导致PC停止工作.
iv、什么是Windows线程,以及Windows线程解决的问题
MS为了解决单个进程执行异常,导致CPU停止工作的问题,设计了Windows线程,它的作用是对CPU进行虚拟化,Windows会给每个Windows进程分配一个Windows线程,该线程相当于一个虚拟的CPU(包含CPU所有的功能),如果应用程序的代码进入死循环,相关进程会被停止,但是其他的应用程序进程并不会停止,会继续执行.因为它们拥有自己的线程(虚拟CPU).
2、Windows线程的消耗
虽然Windows线程保证了Windows的可靠性和健壮性,但是天下没有免费的午餐,随之带来的肯定是其他的PC资源消耗.这里不想介绍太多操作系统级别的东西,只说一些直观的我们能看到的.就以我的笔记本为例,打开任务管理器如下:

我的笔记本此时跑着176个进程,所以理论上至少有176个线程,但是实际却有2103个线程,平均每个进程12个线程.下面是我笔记本的配置

双核,理论上最优的配置是,只有两个线程,应为涉及到线程上下文切换(从一个线程上下文切换到另一个上下文),而上下文的切换的性能代价是十分大的.
我的CPU利用率为7%,说明93%的时间,这2103个线程啥事都没干,严重的浪费了我的内存.如果这个时候开启了远程桌面服务,假设10个用户连了我的笔记本,所有的开销会翻倍.
当然虽然线程的开销很大,但是相比于创建进程,开销相比较小.但是开发应用程序的时候,还是要合理的使用线程!
二、为什么要使用多线程
主要有两点,拿Windows来举例
(1)、Windows使用线程,每个线程拥有一个虚拟的CPU,包含CPU所有的功能,当一个应用程序使用的线程因为代码问题,发生故障时,Windows会关闭这个线程,但是这个线程使用的是虚拟的CPU,所以不会影响其他应用程序使用它们的线程,也就是虚拟CPU.所以线程保证了CPU的高可用.同时现在的电脑往往都有多个CPU,利用这个特性,我们可以使用代码创建多个线程,去执行不同的任务,比如一个Windows桌面程序,可以让主线程去处理用的输入,创建其他的线程去处理桌面程序的UI界面.这样用户体验就会非常好.不会说必须等到桌面UI全部初始化完,用户才能执行输入操作.
(2)、Windows每个CPU就能调度一个线程,如果你的PC有个多CPU,那么它们就能协同操作,同时也就是并发的执行多个任务.但是虽然线程能并发执行很多任务,但是如果创建的线程过多,理论上一个CPU只能调度一个线程,但是你创建的线程如果比CPU还多,那么windows就会进行上下文切换,这个性能损失是很可观的(不考虑创建线程本身的开销),所以关于线程创建的数量,还是需要慎重考虑.
三、关于CPU利用率
CPU利用率简单点说,就是CPU的使用效率,如果当PC长时间的响应I/O,或者在驱动硬件设备干活,而CPU本身却很空闲,这种情况CPU利用率就很低.
四、线程调度和优先级
1、线程调度
首先Windows是一个抢占式的操作系统,抢占式操作系统说白点就是线程的切换,因为大多数Windows操作系统运行了不止一个应用程序,而这些应用程序运行了不止一个线程,最后这些所有的线程加起来肯定超过PC的CPU核数(上面说了一个CPU只能调度一个线程),那么为了保证这些线程能尽可能的同时运行,所以Windows操作系统必须进行频繁的上下文切换,保证这些线程能同时调度.这也就是为什么你在Windows的操作系统同时开启多个应用程序会非常卡的原因.因为一下次有N多个线程同时开启,导致CPU工作压力飙升.
那么为什么说是抢占式的呢?因为每个内核包含一个上下文对象,这个对象包含了线程上次执行完毕的CPU寄存器状态,在一个CPU的时间片执行完毕之后(也就是一个线程执行完毕之后),Windows会便利所有的上下文,找出一个适合调度的上下文,并切换到这个上下文,执行该线程.这就是所谓的抢占式.Windows可以在任何时间抢占当前正在执行上下文,切换到下一个上下文,只要Windows觉得当前上下文更值得被调度。注:这是个很复杂的过程.所以你无法确保创建的线程会在什么时候被调度,以及调度多长时间.这些都由Windows来判断.说白点,它比你更聪明.并且他考虑的比你更全面.哈哈!
2、优先级
虽然你无法确定你的线程什么时候被调度,但是当你有一个线程这个线程执行非常重要的任务,但是Window内核本身并不能保证它的执行优先级,所以我们必须使用其他的手段来确保它能优先于其他线程的执行.万幸的是,Window也考虑到了这一点,设计了优先级这一概念,来满足我们的业务需求.
(1)、进程优先级
Windows支持6个进程优先级类,如下:
Idle(空闲),一般执行在操作系统空闲的时候执行的程序,比如Windows自动更新服务.屏幕保护程序等.
Below Normal(低于普通优先级)
Normal(普通优先级)
Above Normal(高于普通)
Hign(高)如果又非常关键的进程,可以使用.
Realtime(实时,超高优先级)不建议使用,会影响操作系统的进程,会造成"死机"的情况,使用这个优先级有权限要求(管理员有这个权限)
(2)、线程优先级
Windows为线程定义了0~31的优先级,Windows会优先调度高优先级的线程,注意,会存在线程抢占的情况,如果开启了一个应用程序,当该程序里面有一个31优先级的线程,那么Windows会挂起当前正在执行的低优先级的线程,给该线程使用.单核机器,如果存在过多的较高优先级的线程,那么低线程将不会被调度,这是种很shit的情况,所以要谨慎使用.
Windows提供了7个线程优先级
Idle(空闲)操作系统空闲时执行的线程
Lowest(最低级别)
Below Normal(低于正常)
Normal
Above Normal
Hignest
Time-Critical(实时)
(3)、关于进程优先级和线程优先级的联系
真实的线程优先级的大小取决于进程优先级,如果两个进程优先级一样,那么只看线程优先级大小.具体请看CLR via C#提供的这张表

C# 多线程学习系列一的更多相关文章
- .NET并行与多线程学习系列一
并行与多线程学习系列一 一.并行初试: public static void test() { ; i < ; i++) { Console.WriteLine(i); } } public s ...
- 多线程学习系列二(使用System.Threading)
一.什么是System.Threading.Thread?如何使用System.Threading.Thread进行异步操作 System.Threading.Thread:操作系统实现线程并提供各种 ...
- C# 多线程学习系列三之CLR线程池系列之ThreadPool
一.CLR线程池 1.进程和CLR的关系一个进程可以只包含一个CLR,也可以包含多个CLR2.CLR和AppDomain的关系一个CLR可以包含多个AppDomain3.CLR和线程池的关系一个CLR ...
- C# 多线程学习系列二
一.关于前台线程和后台线程 1.简介 CLR中线程分为两种类型,一种是前台线程.另一种是后台线程. 前台线程:应用程序的主线程.Thread构造的线程都默认为前台线程 后台线程:线程池线程都为后台线程 ...
- C# 多线程学习系列四之ThreadPool取消、超时子线程操作以及ManualResetEvent和AutoResetEvent信号量的使用
1.简介 虽然ThreadPool.Thread能开启子线程将一些任务交给子线程去承担,但是很多时候,因为某种原因,比如子线程发生异常.或者子线程的业务逻辑不符合我们的预期,那么这个时候我们必须关闭它 ...
- C#多线程学习(一) 多线程的相关概念(转)
什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程所组成的. 什么是线程?线程是程序中的一个执行流,每个线程都有自己的专有寄 ...
- C#多线程学习(一) 多线程的相关概念
什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程所组成的. 什么是线程?线程是程序中的一个执行流,每个线程都有自己的专有寄 ...
- [转载]C#多线程学习(一) 多线程的相关概念
原文地址:http://www.cnblogs.com/xugang/archive/2008/04/06/1138856.html 什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的 ...
- C#多线程学习(六) 互斥对象
如何控制好多个线程相互之间的联系,不产生冲突和重复,这需要用到互斥对象,即:System.Threading 命名空间中的 Mutex 类. 我们可以把Mutex看作一个出租车,乘客看作线程.乘客首先 ...
随机推荐
- Typecho 独立页面 添加自定义模板
1.首先在主题文件夹新建一个 ***.php 文件 编写代码 <?php /** * _主题命名 * * @package custom * */$this->need('header.p ...
- tp5 excel导出类
1.引入Loader use think\Loader; 2.导出方法: /** * excel表格导出 * @param string $fileName 文件名称 * @param array $ ...
- winform 可拖动无边框窗体解决办法
方法一:通过重载消息处理实现. 鼠标的拖动只对窗体本身有效,不能在窗体上的控件区域点击拖动 /// <summary> /// 通过重载消息处理实现.重写窗口过程(WndProc),处理一 ...
- 20169207《Linux内核原理与分析》第五周作业
这周的任务主要分为两个方面,第一方面,学习MOOC网上视频第三讲并完成配套的实验.第二方面,学习课本的第四章和第六章. 首先从实验开始讲起,前期我们对Linux内核的源码做了一个简单的了解.包括Mai ...
- Java数据类型、赋值、类型转换、==运算
数据类型 基本数据类型:即int/char等这样的数值类型,共8种 引用类型:除了基本数据类型之外都是引用类型:包括API中的类:如String.File:也包括自定义的类:如Personal.ABC ...
- getHibernateTemplate用法
前提条件:你的类必须继承HibernateDaoSupport 一: 回调函数: public List getList(){ return (List ) getHibernateTemplate( ...
- hdu 4135 [a,b]中n互质数个数+容斥
http://acm.hdu.edu.cn/showproblem.php?pid=4135 给定一个数n,求某个区间[a,b]内有多少数与这个数互质. 对于一个给定的区间,我们如果能够求出这个区间内 ...
- [leet code 190]reverse bits
1 题目 Reverse bits of a given 32 bits unsigned integer. For example, given input 43261596 (represente ...
- TextBox Ctrl+A不能全选的问题
问题: 当TextBox控件在设置了MultiLine=True之后,Ctrl+A 无法全选,十分影响使用体验. 对于这个问题不明所以,不知道是Bug,还是故意而为之... 解决1: 添加KeyDow ...
- atom编辑器社区插件推荐
atom是github出品的文本编辑器,为开发者又提供了一款易用.牛逼的文本编译器.在开始接触前端并从工作开始一直用webstrom来进行前端开发,开始使用时,被他各种强大神奇的功能给折服:支持zen ...