[CLR via C#]25. 线程基础
一、Windows为什么要支持线程
- 线程内核对象(thread kernel object) OS为系统中创建的每个线程都分配并初始化这种数据结构。在该数据结构中,包含一组对线程进行描述的属性。 数据结构中还包含所谓的线程上下文(thead context)。上下文是一个内存块,其中包含了CPU的寄存器集合。Windows在一台x86CPU的计算机运行时,线程上下文使用约700字节的内存。对于x64和IA64CPU,上下文分别使用约1240字节和2500字节的内存。
- 线程环境块(thread environment block,TEB) TEB是在用户模式中分配和初始化的一个内存块。TEB耗用1个内存页(x86和x64CPU中是4KB,IA64CPU中是8K)。TEB包含线程的异常处理链首。线程进入的每个try块都在链首插入一个节点。线程退出try块时,会从链中删除该节点。除此之外,TEB还包括线程的"线程本地存储"数据,以及由GDI和OpenGL图形使用的一些数据结构。
- 用户模式栈(user-mode stack) 用户模式栈用于存储传给方法的局部变量和实参。它还包含一个地址:指向当前方法返回时,应该接着从哪个地址开始执行。默认情况下,Windows为每个线程的用户模式分配1MB的内存。
- 内核模式栈(kernel-model stack) 应用程序代码向OS中的一个内核模式的函数传递实参时,会使用内核模式栈。出于安全方面的原因,针对从用户模式的代码传给内核的任何实参,Windows都会把它们从线程的用户模式栈复制到线程的内核模式栈。一经复制,内核就可以验证实参的值,然后进行处理。除此之外,内核会调用它自己内部的方法,并利用内核模式栈传递自己的实参、存储函数的局部变量以及存储返回地址。在32为的Windows运行时,内核模式栈大小为12KB;在64位Windows上运行时,大小为24KB。
- DLL线程连接(attach)和线程分离(detach)通知 Windows的一个策略是,任何时候在进程中创建一个线程,都会调用那个进程中加载的所有DLL的DLLMain方法,并向该方法传递一个DLL_THREAD_ATTACH标识。类似的,任何时候一个线程终止,都会调用进程中的所有DLL的DLLMain方法,并向该方法传递一个DLL_THREAD_DETACH标识。有的DLL需要利用这些通知,为进程中创建和销毁的每个线程执行一些特殊的初始化或资源清理操作。
- 将CPU寄存器中的值保存到当前正在运行的线程的内核对象内部的一个上下文结构中。
- 从现有线程集合中选出一个线程供调度(这个就是要切换到的线程)。如果该线程由另一个进程拥有,Windows在开始执行任何代码或者任何数据之前,还必须切换CPU"看见"的虚拟地址空间。
- 将所选上下文结构中的值加载到CPU的寄存器中。
- 线程需要以非普通线程优先级运行。所有线程池线程都以普通优先级运行;虽然可以改变这种优先级,但不建议这样做。另外,在不同的线程池操作之间,对优先级的更改是无法持续的。
- 需要线程表现为一个前台线程,防止应用程序在线程结束它的任务之前终止。线程池的线程都是后台线程。如果CLR想要终止线程,它们可能被迫无法完成任务。
- 一个计算限制的任务需要长时间运行。线程池为了判断是否需要创建一个额外的线程,所采用的逻辑是比较复杂的。直接为长时间运行的任务创建一个专用线程,则可以避免这个问题。
- 要启动一个线程,并可能调用Thread的Abort方法来提前终止它。
public sealed class Thread : CriticalFinalizerobject,... {public Thread(ParameterizedThreadStart start);//这里没有列出不常用的构造器
}
start参数标识专用线程要执行的方法,这个方法必须和ParameterizedThreadStart委托的签名匹配。
delegate void ParameterizedThreadStart(Oject obj);
internal static class FirstThread {public static void Go() {Console.WriteLine("Main thread: starting a dedicated thread " +"to do an asynchronous operation");Thread dedicatedThread = new Thread(ComputeBoundOp);dedicatedThread.Start(5);Console.WriteLine("Main thread: Doing other work here...");Thread.Sleep(10000); // 模拟做其它工作(10 秒钟)dedicatedThread.Join(); // 等待线程终止Console.ReadLine();}// 这个方法的前面必须和ParametizedThreadStart委托匹配private static void ComputeBoundOp(Object state) {// 这个方法由一个专用线程执行Console.WriteLine("In ComputeBoundOp: state={0}", state);Thread.Sleep(1000); // 模拟其它任务(1 秒钟)// 这个方法返回后,专用线程将终止}
}
- 可以使用线程将代码同其他代码隔离 这将提高应用程序的可靠性。事实上,这正是Windows在操作系统中引入线程概念的原因。
- 可以使线程来简化编码 有的时候,如果通过一个任务自己的线程来执行该任务,编码会变得更简单。通常,在你引入线程时,引入的是要相互协作的代码,它们可能要求线程同步构造知道另一个线程在什么时候终止。一旦开始涉及协作,就要使用更多的资源,同时会使代码变得更复杂。所以,在开发使用线程之前,务必确定线程真的能帮到你。
- 可以用线程来实现并发处理 如果知道自己的应用程序要在多CPU机器上运行,那么让多个任务同时运行,就能提高性能。
线程相对 优先级 |
进程优先级类 |
|||||
---|---|---|---|---|---|---|
Idle |
Below Normal |
Normal |
Above Normal |
High |
Real-Time |
|
Time-critical |
15 |
15 |
15 |
15 |
15 |
31 |
Highest |
6 |
8 |
10 |
12 |
15 |
26 |
Above normal |
5 |
7 |
9 |
11 |
14 |
25 |
Normal |
4 |
6 |
8 |
10 |
13 |
24 |
Below normal |
3 |
5 |
7 |
9 |
12 |
23 |
Lowest |
2 |
4 |
6 |
8 |
11 |
22 |
Idle |
1 |
1 |
1 |
1 |
1 |
16 |
public class Program{public static void Main(){// 创建一个线程 (默认是前台进程)Thread t = new Thread(Worker);// 将前台进程变成后台进程t.IsBackground = true;t.Start(); // 启动线程// 如果t是一个前台进程,则应用程序大约10秒后才终止// 如果t是一个后台进程,则应用程序立即终止Console.WriteLine("Ruturning from Main");Console.Read();}private static void Worker(){Thread.Sleep(10000); // 模拟做10秒钟工作Console.WriteLine("Ruturning from Worker");}}
[CLR via C#]25. 线程基础相关推荐
- 《CLR via C#》之线程处理——线程基础
<CLR via C#>之线程处理--线程基础 <CLR via C#>之线程处理--线程基础 windows为什么要支持线程 线程开销 CPU发展趋势 CLR线程和Windo ...
- C#多线程编程系列(二)- 线程基础
目录 C#多线程编程系列(二)- 线程基础 1.1 简介 1.2 创建线程 1.3 暂停线程 1.4 线程等待 1.5 终止线程 1.6 检测线程状态 1.7 线程优先级 1.8 前台线程和后台线程 ...
- java 线程 操作系统线程_线程基础:线程(1)——操作系统和线程原理
1.概述 我在写"系统间通信技术专栏"的时候,收到很多读者的反馈.其中有一部分读者希望我抽空写一写自己关于对Java线程的使用经验和总结.巧的是,这个月我所在的技术团队也有很多同事 ...
- [CLR via C#]4. 类型基础及类型、对象、栈和堆运行时的相互联系
原文:[CLR via C#]4. 类型基础及类型.对象.栈和堆运行时的相互联系 CLR要求所有类型最终都要从System.Object派生.也就是所,下面的两个定义是完全相同的, //隐式派生自Sy ...
- 线程基础知识——Windows核心编程学习手札系列之六
线程基础知识 --Windows核心编程学习手札系列之六 线程与进程一样由两部分构成:一是线程的内核对象,操作系统用它来对线程实施管理,也是系统用来存放线程统计信息的地方:二是线程堆栈,用于维护线程在 ...
- java线程基础巩固---线程生命周期以及start方法源码剖析
上篇中介绍了如何启动一个线程,通过调用start()方法才能创建并使用新线程,并且这个start()是非阻塞的,调用之后立马就返回的,实际上它是线程生命周期环节中的一种,所以这里阐述一下线程的一个完整 ...
- 线程基础知识系列(三)线程的同步
本文是系列的第三篇,前面2篇,主要是针对单个线程如何管理,启动等,没有过多涉及多个线程是如何协同工作的. 线程基础知识系列(二)线程的管理 :线程的状态,控制,休眠,Interrupt,yield等 ...
- Android多线程研究(1)——线程基础及源码剖析
从今天起我们来看一下Android中的多线程的知识,Android入门容易,但是要完成一个完善的产品却不容易,让我们从线程开始一步步深入Android内部. 一.线程基础回顾 package com. ...
- 进程和线程基础知识(已经是最详细的啦)
进程和线程基础知识 文章目录 进程和线程基础知识 一.前言 二.进程 1.引入 2.并发和并行有什么区别? 3.进程与程序的关系的类比 4.进程的状态 5.进程的控制结构 6.进程的控制 7.进程的上 ...
最新文章
- SQL UPDATE SET FROM用法
- mysq show 指令
- MySQL5.6优化了Order by排序limit
- Spring框架学习笔记04:初探Spring——采用Java配置类管理Bean
- rdlc报表输入中文出现小方块
- 从安装、管理到防御,阿里云安骑士全向测评
- 额外参数_Redis的复制参数学习笔记
- android系统证书管理,抓包Android 7.0+将ca证书导入到系统(设置为系统证书)
- 中科大计算机辅助图形实验室,Prof. Ligang Liu at USTC (中科大刘利刚教授)
- 全部口罩机3D图纸图档打包
- 碎片化NFT研究报告:COSONFT提高NFT流动性的探索和实践
- 计算机电源出现问题,电源故障引起的电脑问题
- C/C++语言——数据类型
- mysql rds 主从_简单说说RDS的主从功能是如何实现
- 微信群打卡小程序_微信打卡小程序上线,你会用吗?
- make: *** [ext/fileinfo/libmagic/apprentice.lo] Error 1
- 「科普」带你认识5G基站
- js JSON.parse和JSON.stringify
- MySQL 数据类型BINARY和VARBINARY
- 【带你敲】演讲比赛流程管理系统