什么是线程
在linux当中线程可以认为是进程的一部分,他与进程共享一份地址空间,而不是新建一个线程就新建一份地址空间(windos操作系统是这样的)。然而,本质上linux是没有线程的概念的,因为CPU在对每个线程处理时,都会把它当作进程来处理,只不过线程在CPU眼里是更轻量级的进程,所以线程只是我们用户理解,在操作系统中他都认为这些是进程,只不过线程可以看作为比进程小一点的进程,下面将画图说明线程在linux中与进程的关系:
上图说明了在Linux系统中线程与进程的关系:
1.线程与进程共用一份地址空间,只不过线程要访问的数据比进程要少,因此他在CPU眼里是属于轻量级的进程。
2.一个PCB就是要被调度的执行流
3.Linux中没有专门为线程设计TCB,而是用进程的PCB来模拟线程
根据进程与线程的关系我们来总结下进程的概念:
进程内部是有多个执行流
创建进程的成本是很高的:时间+空间
创建进程使用的资源很多(0>>>>>1)
以内核视角来看:
进程是承担系统分配资源的基本实体
线程是CPU调度的基本单位,承担进程一部分资源的实体(进程划分资源给线程)
总结一句话就是:进程向系统要资源,而线程是向进程要资源
线程与接口关系的认识
因为Linux是用进程来模拟线程的,因此Linux本身不会提供线程的操作接口,而是给我们提供在同一个地址空间创建PCB的方法,分配资源给指定的PCB的接口。
这样对用户很不友好,因为如果要使用的话用户还要自己创建线程,释放线程,等待线程等,太麻烦。
因此,大佬们为我们在用户层对Linux轻量级进程(线程)接口进行封装,给我们打包成库,让用户直接使用库,原生线程库(用户层)
线程与进程的共享与私有
所有的轻量级进程(可能是"线程")都在进程内部(同一个地址空间:标识进程能看到大部分资源)运行
进程:具有独立性,可以有部分共享资源(管道,ipc资源)
线程:大部分资源是共享的,有部分是私有的(PCB,栈, 寄存器中存储的当前线程的上下文)
线程共享的环境包括:(6个)
(1)进程代码段、(2)进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)、(3)进程打开的文件描述符、(4)信号的处理器、(5)进程的当前目录(6)进程用户ID与进程组ID。
总结:只要记住线程的栈和上下文是私有的其余大部分都是共享的
接下来我们证明下Linux线程是用进程模拟的
首先介绍先创建线程的函数:
注意上面说过使用线程要用到第三方库,因此我们编译时要加上pthread库
运行发现主进程和线程的pid都是25584证明此时只有一个进程,但是有两个执行流!!
kill -9 杀掉该进程两个线程都终止了,再次证明两个执行流是同一个进程的。
下图两个线程的PID是一样的, LWP的意思是轻量级线程,OS内核处理线程时候不看PID,看的是LWP,说明:Linux OS调度的时候看的是LWP,只不过这两个线程在自己的PCB中保存的PID是一样的,证明这两个线程属于同一个进程的,LWP证明了我们两个是不同的执行流!
在只有一个执行流的时候,即只有一个进程,PID == LWP
线程的优点
1.创建一个新线程的代价要比创建一个新进程小得多
2.与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
3.线程占用的资源要比进程少很多
4.能充分利用多处理器的可并行数量
5.在等待慢速I/O操作结束的同时,程序可执行其他的计算任务
6.计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
计算密集型大多数指的是:加密、大数据运算等。主要使用的是CPU资源。但这并不意味这我线程越多,我能同时计算的数据就越多,效率就提升了。
一般使用CPU资源的工作创建多少个线程是要跟自己的CPU核数有关的:CPU核数即一个CPU由多少个核心组成,核心数越多,代表这个CPU的运转速度越快,性能越好。对于同一个数据处理,一核CPU相当于1个人处理数据,双核CPU相当于2个人处理同一个数据,4核CPU相当于4个人去处理同一个数据,因此处理核心数越多,CPU的工作效率也就越高。
如果你是单核的CPU,说明你同时只能处理一个线程,那你最高的效率就是创建一个线程,多了反而会导致线程间被过度切换。
7.I/O密集型应用,为了提高性能,将I/O等待的时间重叠。线程可以同时等待不同的I/O操作。
I/O密集型大多数指的是:网络下载、云盘、在线直播、看电影等。主要用内存外设的IO资源。
IO密集型会允许我们多一些线程,但并不是无脑多,因为进行IO操作,比如我们下载,看电影,大部分时间都在等待IO就绪。比如我们用微信发消息,线程大部分时间都用在等待我们发消息,因此多一些线程,会让我们IO等待的时间重叠,提高效率。
我们大部分的应用都是 计算密集型+I/O密集型这样的应用,最典型的例子:打游戏!!!线程一边要同步大量的数据(I/O),一边还要计算(CPU)!!
线程的缺点
1.性能损失
一个很少被外部事件阻塞的计算密集型线程往往无法与共它线程共享同一个处理器。如果计算密集型线程的数量比可用的处理器多,那么可能会有较大的性能损失,这里的性能损失指的是增加了额外的同步和调度开销,而可用的资源不变。
性能损失既是线程也是进程的缺点。
2.健壮性降低
编写多线程需要更全面更深入的考虑,在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的,换句话说线程之间是缺乏保护的。
一般,你当前进程里有多个线程(执行流),当其中一个线程崩溃了,操作系统会向总进程发信号,而不是出问题的那个线程,导致整个进程都被杀掉了。
3.缺乏访问控制
进程是访问控制的基本粒度,在一个线程中调用某些OS函数会对整个进程造成影响。
因为线程之间的资源大部分是共享的,所以很容易一个线程误操作了其他线程在处理的工作,调试找问题困难。
4.编程难度提高
编写与调试一个多线程程序比单线程程序困难得多
进程和线程的关系如下图: