认识线程

68 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情

​​

1.内存管理

如何理解内存?

26b8439438e44ec3a78c8a9ae28ba33b.png​编辑

物理上是一个内存条,可以存储很多数据

内存可以想象成一个大走廊,有很多小房间,每个房间大小1Byte,并且房间还有编号从0累加,这个内存编号就是地址,这个地址是"物理地址"

内存有一个随机访问的特性,访问内存上的任意数据速度都很快,这个特点造就了数组访问时间复杂度事O(1)

实际上程序并不能直接获取到物理内存

这里我们引入了"虚拟地址空间"

​编辑

直接使用物理内存地址,如果程序出现bug,影响是十分严重的,可能导致访问的内存越界,如果进程一出现访问越界,可能会影响到到进程二的执行,是因为进程之间使用的内存没有进行隔离开,所以可能会相互影响到

针对这个问题引入了''虚拟地址空间'',代码里不直接使用真实的物理地址,使用虚拟出来的地址

由操作系统和专门的硬件设备负责进行虚拟地址到物理地址的转换

​编辑

如果进程一访问越界了,指针地址改变了之后,MMU硬件设备会及时的反馈一个错误,当前地址超出了进程一访问的范围,因此返回一个SIGN SEGEMENT FAULT信号,引起进程一崩溃

所以引入虚拟地址空间,主要是为了避免进程之间相互产生影响,也就是谁出bug了谁就崩溃,每个进程之间就是隔离的了,具有非常重要的意义

MMU是集成在cup中的硬件设备

这样虽然解决了进程间相互影响的问题,但是进程间也是需要数据交互的,所以需要一个"公共空间"来进行数据交互,就能解决进程间的通信问题

2.线程

2.1 认识线程

引入进程是主要目的是为了解决"并发编程"问题,当前cpu进入了多核心时代,为了进一步提高程序的执行速度,就要利用好多核cpu

但是进程消耗的资源和速度相对于线程来说还是慢了很多,进程在资源的分配和回收上的开销非常大,因此线程应运而生,线程也叫做"轻量级进程",它既能解决并发编程的问题,又同时能让创建销毁调度的速度更快一些

线程的轻量在于线程不用申请资源和释放资源,减小了很大一部分开销

每创建一个进程,就好像创建一个工厂,在进程创建一个线程,就好像在一个工厂里增加多条生产线,多条生产线公用一个资源,达到了资源复用的目的

2.2 进程与线程的关系

进程与线程的关系:进程包含线程,一个进程可以包含多个线程,也可以只包含一个线程(不能没有)

当第一个线程启动后,开销是比较大的,但是后面的线程使用的是和第一个线程相同的资源,开销比较小

那么线程使用的资源是哪些?

同一个进程里的所有线程之间,公用的资源:进程拥有的资源,主要包括内存,文件描述符表

也就是线程一申请的内存,后面的线程可以直接使用,线程一打开的文件,后序线程也可以直接使用

发展到现在,操作系统实际调度的时候,是以线程为基本单位来调度的,调度进程就相当与一个进程只有一个线程的情况,如果每个进程有多个线程了,每个线程是在cpu上独立进行调度的

因此,线程是操作系统调度执行的基本单位,每个线程都有自己的执行逻辑

一个线程也是通过PCB来调用的,所以一个进程可能包含多个PCB,但是同一个进程的pid是一样的,内存指针和文件描述符表也是相同的

2.3 线程安全问题

一个进程是可以包含多个线程的,但是增加线程的数量时,也不是一直能提高执行速度,因为cpu核心数量时有限的,线程太多了,核心数目有限,线程调度将会是很大的开销了

系统创建也是需要消耗资源的,创建过多的线程,会导致资源耗尽,别的进程也无法使用了,像cpu,内存,带宽这样的资源

还有一种情况,在不同进程中,每个进程都有自己的资源,不会出现争夺资源的问题,他们的资源都是创建的时候就分配好了,但是线程模型是资源共享的,很容易就触发多线程争抢同一个资源,即一个进程中会出现多线程同时使用一个资源的情况,造成了线程不安全问题

多线程还有另一种情况,当一个线程抛出异常,如果没有处理好,整个进程可能都会崩溃,那么其他线程也寄了