线程基础

一、线程开销

线程有空间(内存耗用)和时间(运行时的执行性能)上的开销
①线程内核对象
OS为系统中创建的每个线程都分配并初始化这种数据结构之一(对线程进行描述的属性、线程上下文)。上下文是包含CPU寄存器集合的内存块。对于x86,x64和ARM CPU架构,线程上下文分别使用约700,1240,和350字节的内存
②线程环境块(TEB)
TEB是用户模式(应用程序代码能快速访问的地址空间)中分配和初始化的内存块。TEB耗用1个内存页(x86,x64和ARM CPU中时4kb)。TEB包含线程的异常处理链首(head)。线程进入每个try块都在链首插入一个节点;线程退出try块时从链中删除该节点。此外,TEB还包含线程的"线程本地存储"数据,以及由GDI和OpenGL图形使用的一些数据结构
③用户模式栈
用户模式栈存储传给方法的局部变量和实参。还包含一个地址;指出当前方法返回时,线程应该从什么地方接着执行。Windows默认为每个线程的用户模式栈分配1MB内存。更具体的说Windows只是保留1MB地址空间,在线程实际需要时才会提交(调拨)物理内存
④内核模式栈
应用程序代码操作系统中的内核模式函数传递实参时,还会使用到内核模式栈。出于对安全的考虑,针对从用户模式的代码传给内核的任何实参,Windows都会把它们从线程的用户模式栈复制到线程的内核模式栈。OS内核代码开始处理复制的值。除此之外,内核会调用它自己内部的方法,并利用内核模式栈传递它自己的实参、存储函数和局部变量以及存储返回地址。在32位Windwos上运行,内核模式栈大小是12kb;64位是24kb
⑤DLL线程连接(attach)和线程分离(detach)通知
Windows的一个策略是,任何时候在进程中创建线程,都会调用进程中加载的所有非托管DLL的DllMain方法,并向该方法传递DLL_THRAND_ATTACH标志。类似的,任何时候线程终止,都会调用进程中的所有非托管DLL的DllMain方法,并向方法传递DLL_THRAND_DETACH标志。有的DLL需要获取这些通知,才能为进程创建/销毁的每个线程执行特殊的初始化或(资源)清理操作。VS在它的进程地址空间加载了大约470个dll!这意味着每次在VS中创建或者销毁一个线程,都必须先调用470个dll函数

Windows任何时刻只将一个线程分配给一个CUP。那个线程能运行一个“时间片”(有时也称为“量”或者“量程”)的长度。时间片到期,Windows就上下文切换到另一个线程

二、使用专用线程

应尽量使用线程池来执行异步的计算限制操作。如果满足一下任何条件则可以使用专用线程
①线程需要以非普通线程优先级运行。所有线程池都以普通优先级运行
②需要线程表现为一个前台线程,防止应用程序在线程结束前终止。线程池始终是后台线程
③计算限制的任务需要长时间运行
④要启动线程,并可能调用Thread的Abort方法来提前终止它

        static void Main(string[] args)
        {
            //创建专用线程
            Thread th = new Thread(ComputeBoundOp);
            th.Start(5);

            th.Join();//等待线程终止
            Console.ReadLine();

        }


        private static void ComputeBoundOp(Object state)
        {
            //这个方法由一个专用线程执行
            Console.WriteLine(state);
            Thread.Sleep(1000);//模拟做其他任务(1秒)
            //这个方法返回后,专用线程将终止
        }

三、线程调度和优先级

只要存在可调度的优先级31的线程,系统就永远不会讲优先级0~30的任何线程分配给CPU。这种情况称为饥饿
较高优先级总是抢占较低优先级的线程

 

进程优先级类

Idle

Below Normal

Normal

Above Normal

High

Realtime

相对线程优先级

 

 

 

 

 

 

 

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

大多数进程时Normal线程时Normal。所以大多数线程的优先级是8

//更改线程的相对线程优先级
th.Priority=ThreadPriority.Normal;

四、前台线程和后台线程

1,一个进程的所有前台线程停止运行时,CLR强制终止仍在运行的任何后台线程
2,前台线程执行确实想完成的任务;后台线程执行非关键性的任务
3,演示前台线程和后台线程的差异

        static void Main(string[] args)
        {
            Thread th = new Thread(ComputeBoundOp);
            th.Start(5);
            th.IsBackground = true;//使用后台线程

            //如果th是前台线程,则应用程序大约3秒后才终止
            //如果th是后台线程,则应用程序立即终止
            Console.WriteLine("bbb");
        }

        private static void ComputeBoundOp(Object state)
        {
            Thread.Sleep(3000);

            //以下这行代码只有在有一个前台线程执行时才会显示
            Console.WriteLine("aaa");
        }

 4,应用程序的主线程以及通过构造一个Thead对象来显示创建的任何线程都默认为前台线程。相反,线程池线程默认为后台线程,另外,由进入托管执行环境的本机代码创建的任何线程都被标记为后台线程

原文地址:https://www.cnblogs.com/zd1994/p/7435449.html