确定不进来学点 操作系统、进程和线程

1️⃣操作系统(Operating System)

操作系统是一组做计算机资源管理的软件的统称。目前常见的操作系统有:Windows系列、Unix系列、Linux系列、OSX系列、Android系列、iOS系列、鸿蒙等。

操作系统由两个基本功能:
1) 防止硬件被时空的应用程序滥用;
2) 向应用程序提供简单一致的机制来控制复杂而又通常大相径庭的低级硬件设备。

1.基本特征

操作系统的基本特征有四个即:并发性、共享性、虚拟性、异步性

(1)并发性

操作系统的并发性是指计算机系统中同时存在多个运行着的程序,因此它应该具有处理和调度多个程序同时执行的能力。在这种多道程序环境下,一段时间内,宏观上有多个程序在同时运行,而在每一时刻,单处理器环境下实际仅能有一道程序执行,故微观上这些程序还是在分时地交替执行。操作系统的并发性是通过分时得以实现的。

并行性则是指两个或者多个事件在同一时刻发生,即两个或者多个事件互不影响,计算机在同一时间完成两种或两种以上的工作,需要在多CPU多核的条件下。

(2)共享性

共享即资源共享,是指系统中的资源可供内存中多个并发执行的进程共同使用。

两种资源共享的方式:

(1)互斥共享方式

系统中的某些资源,虽然可以提供给多个进程使用,但一个时间段内只允许一个进程访问该资源。
如对摄像头设备的共享使用。

(2)同时共享方式

系统中的某些资源,允许一个时间段内有多个进程“同时”对它们进行访问。
所谓的“同时”往往是宏观的,而从微观上讲,这些进程可能是交替地对该资源进行访问的,即分时共享。
如对硬盘资源的共享使用。

(3)虚拟性

指通过某种技术把一个物理实体变成若干个逻辑上的对应物。

虚拟性是一种管理技术,把物理上的一个实体变成逻辑上的多个对应物,或把物理上的多个实体变成逻辑上的一个对应物的技术。采用虚拟技术的目的是为用户提供易于使用、方便高效的操作环境。例如分时系统将一机虚拟为多机就是未来使得用户资源共享更加方便。具体表现为两种虚拟:

(1)虚拟内存:当前要处理的作业所占的内存比计算机的内存小时,先调入部分作业,当这部分作业处理完之后再调入接下来要处理的部分作业,因而程序认为计算机内存足够大,此即虚拟了更大内存
(2)虚拟外设:当计算机连接多个外部设备时,让多个外设工作的时间差在可接受范围内,近似于同时工作,此即虚拟外设。

(4)异步性

指的是系统中并发执行的多道程序“走走停停”即随时可能面对中断,以不可预知的速度向前推进。

在多道程序环境下,允许多个程序并发执行,但由于资源有限,进程的执行不是一贯到底。而是走走停停,以不可预知的速度向前推进,也就是进程的执行顺序和执行时间不确定。这就是进程的异步性。

2.系统调用

(1)什么是系统调用

系统调用是操作系统提供给应用程序使用的接口,可以理解为一种可供应用程序调用的特殊函数,应用程序可以发出系统调用请求来获得操作系统的服务。

(2)系统调用作用

应用程序通过系统调用请求操作系统的服务,服务中的各种共享资源都由操作系统统一掌管,因此在用户程序中,凡是与资源有关的操作(如存储分配、IO操作、文件管理等),都必须通过系统调用的方式向操作系统提出服务请求,由操作系统代为完成。这样可以保证系统的稳定性和安全性,防止用户进行非法操作。

(3)系统调用的分类

设备管理:完成设备的请求,释放,启动等功能
文件管理:完成文件的读写,创建,删除等功能
进程控制: 完成进程的创建,撤销,阻塞,唤醒等功能
进程通信: 完成进程之间的消息传递,信号传递等功能
内存管理: 完成内存的分配,回收,获得作业占用内存区大小及始址等功能

系统调用相关处理涉及到对系统资源的管理,对进程的控制,这些功能需要执行一些特权指令才能完成,因此系统调用的相关处理需要在核心态下进行。

(4)系统调用的级别

进程在系统上的运行分为2个级别:

(1) 用户态(user mode):用户态运行的进程可以直接读取用户程序的数据;

(2) 系统态(kernel mode):系统态运行的程序可以访问计算机的任何资源,不受限制

平常我们的进程几乎都是用户态,读取用户数据,当涉及到系统级别资源的操作(例如文件管理、进程控制、内存管理等)的时候,就要用到系统调用了。

用户态到内核态切换途径

系统调用,中断,异常

2️⃣进程

1. 进程的基础知识

每个应用程序运行于现代操作系统之上时,操作系统会提供一种抽象,好像系统上只有这个程序在运行,所有的硬件资源都被这个程序在使用。这种假象是通过抽象了一个进程的概念来完成的,进程可以说是计算机科学中最重要和最成功的概念之一。

在操作系统内部,进程是操作系统进行资源分配的基本单位

什么是程序?

1.是完成特定任务的一系列指令的集合;
2.是指编译好的二进制文件,在磁盘上,不占用系统资源(cpu,内存,打开的文件,设备,锁);
3.程序是静态的,一般表现为一个或者一组文件,可永久保存。

什么是进程?

1.进程=程序+数据+进程控制块;
2.进程是程序一执行过程,一个程序可以执行多次,表现为多个进程(可“同时”执行);
3.进程是动态的,受到操作系统的的控制,进程会涉及到核心态和用户态的切换。

2.进程控制块抽象(PCB Process Control Block)

进程启动首先需要创建一个PCB。

  • PCB:操作系统管理控制进程运行所用的信息集合。
  • PCB是用来描述进程的数据结构。操作系统为每个进程都维护了一个PCB,用来保存与该进程有关的各种状态信息。
  • PCB是进程存在的唯一标志。

PCB包含信息

  1. 进程标识符信息:它是唯一的,一个进程都必须对应一个PID。PID一般是整形数字
  2. 处理机状态:说明进程当前所处的状态。处理机状态信息主要是由处理机的各种寄存器中的内容组成的。
    包括:① 通用寄存器;② 指令计数器;③ 程序状态字PSW;④ 用户栈指针。
    这些信息显然和进程相关,因此,进程一旦被中断,就必须把这些信息保存在PCB中,以便在恢复运行时能完全恢复中断前的状态。
  3. 进程调度信息
    在PCB中还存放一些与进程调度和进程对换有关的信息,包括:
    ① 进程状态;
    ② 进程优先级;
    ③ 进程调度所需的其它信息,它们与所采用的进程调度算法有关,比如,进程已等待CPU的时间总和、进程已执行的时间总和等;
    ④ 事件,指进程由执行状态转变为阻塞状态所等待发生的事件,即阻塞原因。
  4. 进程控制信息
    ① 程序和数据的地址;
    ② 进程同步和通信机制,指实现进程同步和进程通信时必需的机制,如消息队列指针、信号量等,它们可能全部或部分地放在PCB中;
    ③ 资源清单,即一张列出了除CPU以外的、进程所需的全部资源及已经分配到该进程的资源的清单;
    ④ 链接指针,它给出了本进程(PCB)所在队列中的下一个进程的PCB的首地址。

3.进程调度

操作系统调度进程,对应有很多种调度算法:

  1. 先来先服务:根据时间顺序来执行
  2. 高优先级算法:优先级高的进程,优先执行。(指的是总的优先级,简单认为可以是进程优先级信息+进程等待信息)
  3. 短作业有线:执行的剩余时间越短,就优先执行。
  4. 时间片轮转调度算法:系统将所有的就绪进程按先来先服务的原则排成一个队列,每次调度时,把CPU分配给队首进程,并令其执行一个时间片;当执行的时间片用完时,由一个计时器发出时钟中断请求,调度程序便停止该进程的执行,并将其放就绪队列尾;然后,再把处理机分配给就绪队列中新的队首。

4.进程的状态

新建态:刚刚创建的进程就处于新建状态
就绪态:处于就绪队列,等待被CPU执行的进程的状态就是就绪态。比如新创建的进程放入就绪队列或者时钟到期CPU将未执行完的进程放入就绪队列
运行态:如果被CPU调度执行,就是运行状态
阻塞态:运行中被阻塞,则处于阻塞态,比如I/O读,或者等待键盘输入等
终止态:进程的所有指令执行结束,但PCB暂时保留,OS还有其他的一些操作

五状态转移图

可能的状态转移

->新建:随着程序的启动运行,一个新进程被创建时的第一个状态;
新建 -> 就绪:进程的初始化工作全部完成(由OS的指令完成的)
就绪 -> 运行:处于就绪状态的进程被操作系统的进程调度器选中后,就分配给 CPU 正式运行该进程;
运行 -> 结束:当进程已经运行完成或出错时,会被操作系统作结束状态处理
运行 -> 就绪:1.被高优先级的进程抢占了 2.时间片耗尽 3.进程执行一些OS提供的系统调用,主动放弃
运行 -> 阻塞:等待一些外部条件:等待IO设备;进程休眠一段时间等等
阻塞 -> 就绪:外部条件满足:有IO数据;休眠时间结束…
结束 -> :进程PCB彻底被OS回收

就绪队列:装有所有处于就绪状态的进程,等待着被分配CPU,就绪队列一般只有一个。
阻塞队列:等待某些外部条件唤醒的进程组成的队列,阻塞队列一般每个条件都可以有一个。

5.进程上下文切换

进程是由内核管理和调度的,所以进程的切换只能发生在内核态。

所以,进程的上下文切换不仅包含了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的资源。

通常,会把交换的信息保存在进程的 PCB,当要运行另外一个进程的时候,我们需要从这个进程的 PCB 取出上下文,然后恢复到 CPU 中,这使得这个进程可以继续执行,如下图所示:

进程上下文切换的场景

  • 为了保证所有进程可以得到公平调度,CPU 时间被划分为一段段的时间片,这些时间片再被轮流分配给各个进程。这样,当某个进程的时间片耗尽了,就会被系统挂起,切换到其它正在等待 CPU 的进程运行;
  • 进程在系统资源不足(比如内存不足)时,要等到资源满足后才可以运行,这个时候进程也会被挂起,并由系统调度其他进程运行;
  • 当进程通过睡眠函数 sleep 这样的方法将自己主动挂起时,自然也会重新调度;
  • 当有优先级更高的进程运行时,为了保证高优先级进程的运行,当前进程会被挂起,由高优先级进程来运行;
  • 发生硬件中断时,CPU 上的进程会被中断挂起,转而执行内核中的中断服务程序;

6.虚拟内存

物理内存与虚拟内存建立联系通过地址映射得来。所谓映射,就是一个地址转换的过程,通俗地讲,就是让虚拟地址与物理地址建立一一对应的关系。一旦这种关系建立,进程只需操作虚拟地址即可,然后通过查找这一虚拟地址与实际地址建立的关系,即可实现对实际地址的使用。当进程退出不需要内存资源释放时,将这一对应关系断开即可,此时虚拟地址就毫无意义,因为它没有和任何物理地址有关系。

系统虽然为每一个进程分配了4GB的虚拟内存空间,但实际情况是进程按照当前运行对内存的需求,通过与实际的物理内存建立映射关系,获取分配的内存资源。在这一过程中,所需的地址在其生命周期中可以发生变化。同时,虚拟内存使得进程认为它的拥有连续可用的内存(一段连续完整的内存);但实际上,它通常是映射的多个不连续的物理内存分段来的。

而且虚拟地址的存在让程序员不用关心多次运行的程序地址不同带来的复杂性。通过虚拟内存,让内存管理单元对进程的地址进行管理,减轻程序员的负担。

7.进程资源的分配

CPU 分配 —— 进程调度(Process Scheduling)

为了便于讨论和理解,我们大部分的场景下假设是单CPU单核的计算机。
操作系统对CPU资源的分配,采用的是时间模式 —— 不同的进程在不同的时间段去使用 CPU 资源。

内存分配 —— 内存管理(Memory Manage)

操作系统对内存资源的分配,采用的是空间模式 —— 不同进程使用内存中的不同区域,互相之间不会干扰。

8.进程间通信(Inter Process Communication)

进程是操作系统进行资源分配的最小单位,这意味着各个进程互相之间是无法感受到对方存在的,这就是操作系统抽象出进程这一概念的初衷,这样便带来了进程之间互相具备”隔离性(Isolation)“。

但现代的应用,要完成一个复杂的业务需求,往往无法通过一个进程独立完成,总是需要进程和进程进行配合地达到应用的目的,如此,进程之间就需要有进行“信息交换“的需求。进程间通信的需求就应运而生。

目前,主流操作系统提供的进程通信机制有如下:

  1. 管道(pipe)
  2. 共享内存(shared memory)
  3. 消息队列(mesage queue)
  4. 网络(network)
  5. 信号量(semaphore)
  6. 信号(signal)

其中,网络是一种相对特殊的 IPC 机制,它除了支持同主机两个进程间通信,还支持同一网络内部非同一主机上的进程间进行通信。

3️⃣线程

1.什么是线程

一个线程就是一个 “执行流”. 每个线程之间都可以按照顺讯执行自己的代码. 多个线程之间 “同时” 执行
着多份代码.

执行流:拥有独立PC的一个或一组指令/语句。

举个栗子:
一家公司要去银行办理业务,既要进行财务转账,又要进行福利发放,还得进行缴社保。
如果只有张三一个会计就会忙不过来,耗费的时间特别长。为了让业务更快的办理好,张三又找来两位同事李四、王五一起来帮助他,三个人分别负责一个事情,分别申请一个号码进行排队,自此就有了三个执行流共同完成任务,但本质上他们都是为了办理一家公司的业务。
此时,我们就把这种情况称为多线程,将一个大任务分解成不同小任务,交给不同执行流就分别排队执行。其中李四、王五都是张三叫来的,所以张三一般被称为主线程(Main Thread)。

2.为什么要有线程

首先, “并发编程” 成为 “刚需”.

  • 单核 CPU 的发展遇到了瓶颈. 要想提高算力, 就需要多核 CPU. 而并发编程能更充分利用多核 CPU 资源. 有些任务场景需要
  • “等待 IO”, 为了让等待 IO 的时间能够去做一些其他的工作, 也需要用到并发编程.

其次, 虽然多进程也能实现并发编程, 但是线程比进程更轻量.

  • 创建线程比创建进程更快.
  • 销毁线程比销毁进程更快.
  • 调度线程比调度进程更快.

3.进程与线程的关系

线程是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。

与进程不同的是同类的多个线程共享进程的方法区资源,但每个线程有自己的程序计数器(PC)虚拟机栈本地方法栈,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。

4.线程和JVM内存模型

a) 程序计数器(PC寄存器)

由于在JVM中,多线程是通过线程轮流切换来获得CPU执行时间的,因此,在任一具体时刻,一个CPU的内核只会执行一条线程中的指令,

因此,为了能够使得每个线程都在线程切换后能够恢复在切换之前的程序执行位置,每个线程都需要有自己独立的程序计数器,并且不能互相被干扰,否则就会影响到程序的正常执行次序。

因此,可以这么说,程序计数器是每个线程所私有的。由于程序计数器中存储的数据所占空间的大小不会随程序的执行而发生改变,因此,对于程序计数器是不会发生内存溢出现象(OutOfMemory)的。

b) java栈

Java栈中存放的是一个个的栈帧,每个栈帧对应一个被调用的方法,在栈帧中包括局部变量表、操作数栈、指向当前方法所属的类的运行时常量池的引用、方法返回地址 和一些额外的附加信息。当线程执行一个方法时,就会随之创建一个对应的栈帧,并将建立的栈帧压栈。当方法执行完毕之后,便会将栈帧出栈。

c)本地方法栈

Java 中有些代码的实现是依赖于其他非 Java 语言的(C++),本地方法栈存储的是维护非 Java 语句执行过程中产生的数据,一般我们认为本地方法栈不会出现内存的问题。

为了保证线程中的局部变量和数据不被别的线程访问到,虚拟机栈和本地方法栈是线程私有的

d)堆

Java中的堆是用来存储对象本身的以及数组(数组引用是存放在Java栈中的)。堆是被所有线程共享的,前提是该线程持有该对象的引用,在JVM中只有一个堆。

e)方法区

与堆一样,是被线程共享的区域。在方法区中,存储了每个类对象(.calss)(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。

在Class文件中除了类的字段、方法、接口等描述信息外,还有一项信息常量池,用来存储编译期间生成的字面量和符号引用。

在方法区中有一个非常重要的部分就是运行时常量池,它是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,对应的运行时常量池就被创建出来。

当然并非Class文件常量池中的内容才能进入运行时常量池,在运行期间也可将新的常量放入运行时常量池中,比如String的intern方法。

5.进程和线程的区别

  • 本质:进程是操作系统资源分配的基本单位;线程是任务调度和执行的基本单位
  • 内存分配:系统在运行的时候会为每个进程分配不同的内存空间,建立数据表来维护代码段、堆栈段和数据段;除了 CPU 外,系统不会为线程分配内存,线程所使用的资源来自其所属进程的资源
  • 资源拥有:进程之间的资源是独立的,无法共享;同一进程的所有线程共享本进程的资源,如内存,CPU,IO 等
  • 开销:每个进程都有独立的代码和数据空间,程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行程序计数器和栈,线程之间切换的开销小
  • 通信:进程间 以IPC(管道,信号量,共享内存,消息队列,文件,套接字等)方式通信 ;同一个进程下,线程间可以共享全局变量、静态变量等数据进行通信,做到同步和互斥,以保证数据的一致性
  • 调度和切换:线程上下文切换比进程上下文切换快,代价小
  • 执行过程:每个进程都有一个程序执行的入口,顺序执行序列;线程不能够独立执行,必须依存在应用程序中,由程序的多线程控制机制控制
  • 健壮性:每个进程之间的资源是独立的,当一个进程崩溃时,不会影响其他进程;同一进程的线程共享此线程的资源,当一个线程发生崩溃时,此进程也会发生崩溃,稳定性差,容易出现共享与资源竞争产生的各种问题,如死锁等
  • 可维护性:线程的可维护性,代码也较难调试,bug 难排查

6.线程的优缺点

多线程的优点

  • 使用线程可以把占据时间长的程序中的任务放到后台去处理
  • 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
  • 程序的运行速度可能加快
  • 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下可以释放一些珍贵的资源如内存占用等等。
  • 多线程技术在IOS软件开发中也有举足轻重的位置。

多线程的缺点

  • 如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换。
  • 更多的线程需要更多的内存空间。
  • 线程可能会给程序带来更多“bug”,因此要小心使用。
  • 线程的中止需要考虑其对程序运行的影响。
  • 通常块模型数据是在多个线程间共享的,需要防止线程死锁情况的发生。

7.进程和线程的选择

  • 需要频繁创建销毁的优先使用线程。因为进程创建、销毁一个进程代价很大,需要不停的分配资源;* 线程频繁的调用只改变 CPU 的执行
  • 线程的切换速度快,需要大量计算,切换频繁时,用线程
  • 耗时的操作使用线程可提高应用程序的响应
  • 线程对 CPU 的使用效率更优,多机器分布的用进程,多核分布用线程
  • 需要跨机器移植,优先考虑用进程
  • 需要更稳定、安全时,优先考虑用进程
  • 需要速度时,优先考虑用线程
  • 并行性要求很高时,优先考虑用线程

8.Java 的线程 和 操作系统线程 的关系

线程是操作系统中的概念. 操作系统内核实现了线程这样的机制, 并且对用户层提供了一些 API 供用户使用(例如 Linux 的 pthread 库).
Java 标准库中 Thread 类可以视为是对操作系统提供的 API 进行了进一步的抽象和封装.

Java 线程 VS OS线程

OS针对同一个进程下的线程实现“连坐”机制,一旦一个线程异常退出,OS会关闭该线程所在的整个进程。

对于Java线程不同的JVM有不同的实现,它们的外在表现基本一致,除极个别的几个现象。
JVM使用的HotSpot实现使用一个OS线程来实现一个Java线程。
Java线程中,一个线程异常关闭,不会连坐,同时Java中的线程还克服了很多OS线程的缺点。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

bruin_du

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

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

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

打赏作者

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

抵扣说明:

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

余额充值