【多线程】进程以及进程和线程之间的区别和联系

本文深入介绍了操作系统的概念及其重要性,详细讲解了进程和线程的区别与联系。进程作为执行的程序,由PCB(进程控制块)描述,包括PID、内存指针和文件描述符表等属性。操作系统通过双向链表管理进程,实现并发和并行。线程作为进程的一部分,更加轻量,允许更高效的资源利用。进程间通信通过公共空间实现,如文件和网络操作。线程共享进程资源,提高了并发性能,但也可能导致资源竞争。
摘要由CSDN通过智能技术生成

1.操作系统的介绍:

首先操作系统是一个软件同时操作系统是计算机上最重要,也是最复杂的软件之一。我们在日常中也见过许多的操作系统类似于: Windows,Linux,mac,Android.ios,openwrt.(有些童鞋会说,那还有我们现在华为最火的鸿蒙系统嘛,其实所谓的鸿蒙系统就是安卓系统的换皮。鸿蒙是否认为是一个独立的系统,商业宣传的层面更多一些,技术层面更少一些,在华为这个公司相当于奇数人员来说,销售更加厉害,华为的销售在华为圈子里可谓是人上人)

操作系统到的主要作用:

对上:要提供一个提供软件稳定运行的一个工作环境。
对下:要管理好各种硬件资源(例如:CPU,硬盘等硬件)
如图:
在这里插入图片描述

2.进程

2.1 进程相关概念

什么是进程呢?
其实进程就是一个跑起来的程序(被执行的程序)。
我们可以打开电脑中的任务管理器,选择进程,就可以看到此时电脑执行的程序。

同时我们也可以在一个软件安装包中,看到.exe文件,该文件就是一个可执行文件.

  • 如果我们此时没有双击打开该文件,那么此时它就在磁盘上。
  • 如果我们双击打开该文件此时操作系统就会把.exe文件加载到内存中,并且让cpu执行.exe文件中的一些二进制指令。这个时候,就已经把.exe文件给执行起来了,它就不再是躺在硬盘上的咸鱼了,而是开始进行了一些具体的工作我们把这些运行起来的可执行文件,称为进程,进程(process)又被称为任务(task)

2.2 什么是线程:

首先 线程是进程中的一部分, 进程包含线程,如果把进程看做是一个工厂,那么此时的进程就是工厂中的一个流水线
我们平常写的代码,最终的目的是跑起来,最终都是要成为一些进程。
对于java代码来说,最终都是通过java进程来跑起来的,(此处我们讲的java进程就是大家熟知的JVM)

2.3 操作系统是如何管理进程的?

2.3.1先描述一个进程(明确一个进程中的一些相关属性)

操作系统使用c/c++实现的,这里的进程描述其实就是c语言中的一个结构体(也和java中的类差不多),在操作系统中描述进程这个结构体,被称为"PCB"(process control block),这里的PCB库不是我们家里在装修的时候,需要使用得到PCB板,它是进程控制块

2.3.2 再组织若干个进程(使用一些数据结构,把很多的描述进程的信息给放到一起,方便进行增删查改)

典型的实现,就是使用双向链表来把每个进程的PCB给串起来。当然操作系统的种类是有很多的。内部的实现也是各有不同,咱们此处所讨论的情况,是Linux这个系统为例,那么这是为什么呢?其实就是应为windows,mac这样的系统,不是开源的,我们看不到实现系统的代码,里面是啥情况,咱们也不知道。
所谓的创建进程: 先描述出一个PCB,然后将PCB添加到双向链表中。
所谓的删除进程: 在双向链表中找到该进程对应的PCB描述,然后进行删除。
所谓的查看任务管理器: 实则就是遍历双向链表。

2.3.3 PCB(进程控 制块)中的一些属性:

2.3.3.1 pid(进程id): 进程的身份标识(进程的身份证号)。

在这里插入图片描述

2.3.3.2 内存指针:

指明了该进程要执行的哪些代码,指令内存在哪里,以及这个进程执行中依赖的数据在哪里。(当运行一个.exe文件,此时操作系统就会把.exe文件加载到内存中,变成进程程)

2.3.3.3 文件描述符表:

在程序执行的时候,经常要和文件打交道(文件在磁盘上)(打开文件,读写文件,关闭文件),进程每打开一个文件,就会在文件描述符表中多添加一项。(这个文件描述符表就相当于一个数组,里面的每个元素又是一个结构体,每个结构体描述一个文件的相关信息)。
只要一个进程一旦启动,不管是否有没有写打开操作文件的代码,系统都会默认打开3个文件(标准输入System.in,标准输出System.out,标准错误System.err),文件描述符表的下标被称为文件描述符。

如何让一个进程正常工作?

要想让一个进程正常工作,系统必须分配一些资源,比如内存,硬盘,CPU

上面的属性是一些基础的属性,下面的一组属性,主要是为了能够实现进程的调度

进程调度: 这是理解进程管理的重要话题,操作系统在考虑CPU资源如何给各个进程如何分配。
所谓的进程调度,针对的是多任务操作系统(同一时间,多个进程在执行个各自进程中的代码),而单任务操作系统,同一时间只能执行一个线程中的代码,对于单任务操作系统来说不存在进程调度。我们现在的操作系统大多都是“多任务操作系统”,一个系统同一时间,可以执行多个任务 ,像我们的windows系统,就是多任务的,同一时刻,很多进程在执行,当我们使用计算机的时候,打开画图板和qq音乐等应用,那么此时计算机就会同时执行这个几个进程。
但是在早些年,博主还在上小学的时候,就有“单任务操作系统”,同一时间只能运行一个进程。像在早些年使用的国产山寨机就是单任务操作系统,不需要考虑进程调度。我们系统上的任务的数量(进程的数量),有几十个,上百个,但是我们的CPU的核数就那么几个(我的电脑是6核的),那么这用6核的CPU怎么才能执行庞大的任务量呢?这就不得不说并行和并发 了。

并行和并发

以上所说多任务操作系统,指的是在同一时间可以调度多个进程,其实也就是并行,并发。
并行: 指的是在同一时刻,多个指令在多个处理其中执行。
并发: 指的是在同一时刻,只有只有一条指令在执行,但是多条指令快速轮转进行执行,这样就从宏观的角度上,看做是同一时间,多条指令在执行。例如,从微观上,一个CPU核心,先执行任务1一会,再执行任务2一会,在执行任务3一会,在执行任务2一会。只要CPU核心执行任务,切换的做够快,就好像同一时刻,执行多条任务。

并行和并发在宏观上区分不了,在微观上是操作系统自行调度的结果

就好比有6个CPU核心,20个任务。有些是并行关系,有些是并发关系,有的可能任务A和任务B一会是并发,一会是并行。都是微观上操作系统在控制的,在宏观上感知不到。
咱们只是在研究操作系统进程调度这个话题的时候,稍作区分,但是在其他场景基本都是使用并发,作为一个统一来代替的。
进程调度分为:状态,优先级,上下文,记账信息

状态

描述当前进程接下来应该怎样进行调度。
就绪:-随时可以去CPU上执行。
阻塞/睡眠状态:暂时不可以去CPU上执行。

这里博主形象的举一个例子,以便以后复习使用
所谓的调度,就是“时间管理”
假设博主现在是一个妹子,长得好看,身材也好,还是一个会说话的妹子。这样我就会有很多的追求者。
我现在要谈男朋友,在原则上同一时间,我只能谈一个男朋友。但是我想要既有钱,好长得帅,还会舔我的男朋友,但是在生活中,同时满足这三点的,还是非常不科学的。于是博主就成了一个渣女
我可以同时谈多个男朋友,假设我同时谈了三个男朋友
A:有钱的 B:长得帅的 C:比较会舔的>于是我就需要合理的管理时间,不能让这几个男朋友碰到了,如果碰到了,我岂不就完了嘛。
于是我列了一个时间表 周一:和A去逛街 周二:和B去上课 周三:和C去看电影…
在宏观上我同时谈了三个男朋友
在微观上,同一时刻,我只是和一个男朋友在一起。
这里对应上述状态的就是这个例子: 正常情况下,这 A,B,C三个人我都是随叫随到的(这就是就绪状态) 但是假设A要出差一个月,此时就成认为A是阻塞状态/睡眠状态,因此处于这样状态的进程,就暂时不进行调度(暂时不把这个A给安排到时间表上)

优先级:

先给那个进程分配时间,后给那个进程分配时间,以及分配时间的多少。

正所谓,人之常情,和长得帅的逛街,倍有面子,和有钱的逛街就会收货满满,那么我现在就要给我的男朋友分配优先级,周一到周三,都和B在一起,周四和周五和A在一起,周六和C在一起,周天就给自己放一天假。这样我在我的时间表上就是优先给B牌,其次给A牌,最后给C排。

记账信息:

统计每个进程执行了多久,每个进程执行了那些指令,每个进程的排队时间有多久。给进程调度提供依据。

还是利用上面渣女的例子:上面不是说了嘛,我列了一个时间表,但是如果场次以往,和C在一起的时间就会太少了(毕竟动不动让别人舔一舔,也是挺舒服的),C对我的好感度就会降低,填的也不卖力了,这个时候我就可以根据本子上排的时间,就会发现给C排的时间太少了,接下来就适当的给C一点甜头。

上下文:

表示的是 上次进程在被CPU调度之后,当时进程的执行状态。下次进程在CPU上执行的时候,就可以恢复上次的状态,然后继续向下执行,这就好比是有童鞋在玩手机上的单机游戏,游戏打完之后进行存档,以便于在下次在玩游戏的时候,以前游戏中的数据还在。在第二次玩游戏的时候,就相当于读档。

还是上面的例子:
某一天A给我说,下个月,要带我去夏威夷度假,让我提前做点准备。
下一天,B给我说,下周,他外婆过生日,也希望我准备准备。
过了几天后,A和我提起,你准备的咋样,我说礼物准备好了,,,,,A:礼物,什么礼物,这时候我才意识到,不好,我串台了
所以说:要怎样区分呢?
就把相应的事情记到本本上,就不会搞错了。
养成记录日记的好习惯,就把每次约会的重要心意都记录下来,下次再和他梦见面的时候,就能对的上号了,哪怕时间长一点,也无所谓。当我把重要的事情写到本本里的时候,就是存档,当我要查看本本中的内容的时候,就是读档
存档: 在进程被调出之前,把CPU上所有寄存器中的数据全部保存在内存中(PCB的上下文字段中)
读档: 下次进程在被CPU调度的时候,就可以把刚才内存中的数据恢复到CPU中的寄存器中
进程的调度,其实就是操作系统,在考虑CPU资源如何给各个进程分配。

2.4 进程的独立性

在多任务操作系统中,同一时刻,多个进程在执行各自的代码。
如果某个进程在执行的时候出现了bug,那么其他的进程是否会受到影响?
其实是不会的,这正是因为进程具有独立性。两个进程之间是相互隔离的,不可以直接进行交互*** 。
进程的独立性,就依仗了虚拟地址空间
如果进程1出现了bug,那么进程2,和进程3不会受到影响,继续执行各自进程中的代码。
这里举一个栗子!
在这里插入图片描述

假设疫情期间,一栋楼中出现了一个居民核酸变成了阳性。那么是否会影响到其他的居民呢?
一旦发现有人阳性了,就需要立刻封楼,分小区,否则就会导致其他人也会被传染。
这个情况类似于早期的操作系统,早期的操作系统,里面的进程都是访问的同一个内存地址空间。如果某个进程出现了bug,,把某个内存数据也会被写错,就会可能引起其他的进程出现崩溃
那么现在的解决方案就是,在这个院子里,给划分出几条道路,这些道路之间彼此隔离开来,每个人走各自的道路,这时候就没事了,这样即使有人确诊,但是也不影响到别人。

那么此时就有一个问题:如果把进程按照虚拟地址空间的方式给划分出很多份,这个时候不是每一份就只剩下一点了吗?
其实,虽然你的操作系统有百八十个进程,但是实际上从微观上看,同时执行的进程也只有6个(因为CPU核心只有6个),其实每个进程能够捞找的内存挺多的,而且另一方面,也不是所有的进程都是那么多的内存,比如说有的进程(比如说一个大一点的游戏吧,吃几个G),但是大多数的进程也就是只占几M而已。

2.5 进程间通信

两个进程之间是相互隔离的,不可以直接进行交互。
在这里也举一个例子。

就比如说:现在疫情期间,外出采购有限制,但是我现在要做饭,没有土豆了,于是我就就想,找其他业主借一点,但是我和其他的业主由于疫情期间不能相互接触,所以此时就想出了一个办法,建一个公共空间,这个空间是任何居民都可以来访问的。
如图:
在这里插入图片描述
现在小区外面有一个公共空间,于是业主B就把我需要的菜,放到公共空间中,然后进行消毒,然后我在从这个公共空间把菜取走,彼此之间就不容易传染
这个例子就可以用到进程间的通信中,在操作系统,提供的“公共空间有很多”,并且个具有特点。有的存储量大,有的存储量小,有的速度快,有的慢,其实操作系统中提供了多宗的进程间通信机制(有些机制由于历史遗留原因,已经不适合先到的程序开发了)

进程A可以把数据先放到公共空间,当线程B执行的时候,在取走公共空间中线程A中的某些数据。
主要的进程间通讯方式:文件操作,网络操作。

3.线程

3.1 为什么要使用线程

因为如果频繁的创建销毁进程,还有频繁的调度线程成本比较高。
创建进程,和销毁进程就要分配资源(内存+文件)
对于资源的申请和释放本事就是一个比较低效的操作

那么如何解决这个问题呢?
方法一:

进程池:进程池虽然解决了效率低的问题,但是也引来了新的问题,就是在进程池中的闲置进程不使用的时候,在消耗系统资源

方法二:

使用线程来实现并发并发编程。
线程包含在进程中,一个进程可以有多个线程。线程比进程更加轻量。每个进程可以执行一个任务,每个线程同样也可以执行一个任务,也能实现并发编程。
创建,销毁,调度线程要比创建,销毁,调度进程要高效的多。

3.2 为什么线程要比进程更加轻量

因为进程有资源的申请和释放。
线程在进程中包含,一个进程中的线程,共用一份资源。(同一份内存和文件),只要创建进程的第一个线程的时候此时要申请资源,成本会高一些,当以后的每个线程在创建的时候,成本就会低一些。(不用分配资源)
那么就会有的童鞋问,那么就把线程多创建一些,这样效率不就更好的提升了吗?
其实一般来说是会提高效率的,但是在一个进程中创建多个线程的话,线程和线程之间就会竞争资源。这个时候整体的速度就会受到限制,因为整体的硬件资源是有限的。如果还要想提高效率,那么此时就要添加新的内存资源

3.3 线程和进程的联系和区别

  1. 线程包含在进程中,一个进程可以有一个线程,也可以有多个线程。
  2. 进程和线程都是为了处理并发这样的场景,但是进程,资源被频繁的创建和时释放的时候,效率低下。相比之下进程中的线程就更加轻量(少了申请释放资源的过程)
  3. 操作系统创建进程,要给进程分配资源,进程是操作系统分配资源的基本单位。操作系统创建线程,是在CPU调度执行的,线程是操作系统调度执行的基本单位(咱们前面讲的时间管理,但是咱们调度的进程,但是更准确的说,其实就是调度的线程,前面的例子相当于一个进程中只有一个线程,可以视为调度进程,但是如果进程中有多个线程,更严谨的说法即使,还是以线程为单位进行调度)
  4. 进程具有独立性,每个进程都有自己的虚拟内存空间,一个进程挂了,不会影响其他的进程执行代码
  5. 线程不是独立的,一个进程中的线程,共用一块资源,一旦一个线程挂了,可能会影响带其他的线程,甚至可能让整个进程崩溃。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小周学编程~~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值