操作系统最核心的概念就是进程,进程是对运行中的程序的一个抽象,是动态的。每一个核能够一次运行一个线程,理论上是可以实现并行。
而进程中最重要的是PCB,PCB是操作系统为之配的专门的数据结构。PCB描述了进程的基本情况和活动过程,进而控制管理进程。
进程
进程的创建
进程的创建,就是创建进程实体中的PCB。在UNIX中,仅有一个系统调用用来创建一个新的进程,就是fork,在fork后,一个父进程和子进程会有相同的内存映像,相同的环境字符串和相同的打开文件。
内存映像:内核如何在内存中存放可执行程序文件
进程的终止
自愿退出:进程完成工作后创建系统调用exit。
被其他进程杀死:kill
错误退出
进程的层级结构
在一些系统中,当一个进程创建了其他进程后,父进程和子进程会以某种方式关联。子进程也可以创建更多进程,从而形成一个进程层级结构。
在UNIX中,进程和它的所有子进程以及子进程的子进程共同组成一个进程组。整个操作系统都隶属与以init为根的进程树。
Window不存在层级结构
进程状态
进程三个状态:就绪态,执行态,阻塞态:
就绪态:得到了除CPU以外的所有应该具备的资源,得到CPU便进入执行态
执行态:进程实际占用CPU
阻塞态:由于某种外部时间发生,进入阻塞。
进程的实现
操作系统为了执行进程间的切,会维护一张进程表。每个进程占用一个表项。该表项包含了进程状态的重要信息,如程序计数器、堆栈指针······等。
进程中断处理和调度的过程:
- 硬件压入堆栈程序计数器
- 硬件从中断向量装入新的程序计数器
- 汇编语言过程保存寄存器的值
- 汇编语言过程设置新的堆栈
- C中断服务程序运行
- 调度器决定下面那个程序运行
- C过程返回汇编
- 汇编语言过程开始运行新的进程
线程
有了进程为什么还要用线程的存在?
- 多线程会共享一个地址空间和所有可用的数据
- 线程要比进程更轻量级,创建和销毁速度块
- 从性能上讨论,如果存在大量的除CPU以外资源的处理,多个线程可以并行运行,提高执行速度。
线程的模型
进程是资源分配的最小单位,线程是CPU调度的最小单位。
线程会共享一个地址空间。
线程不具备像进程一样的独立性。但是同一个进程下的不同线程也有自己的东西。
进程中的内存,线程可以共享,但是每个线程也有自己的堆栈,状态等等。
线程的系统调用
thread_create: 创建线程,返回线程标识符(即线程名字)
thread_exit: 退出线程
thread_join: 线程的加入,可以在线程运行中执行函数,表示一个线程可以等待另一个线程的退出
thread_yeild: 允许线程主动放弃CPU
POSIX线程
目前还不是很懂什么POSIX,是IEEE设定支持在UNIX操作系统上软件的API的协议规定?
线程的实现
主要三种实现方式
- 在用户空间实现线程
- 在内核空间实现线程
- 在用户和内核混合实现线程
在用户空间实现线程
特点:就是将线程整个抱在用户空间中,内核对线程一无所知。从内核角度考虑,就是按正常的方式管理,即单线程进程
优点:
1、用户级线程包可以在不支持线程的操作系统上实现
2、线程切换比内核快更多
3、允许每个进程有自己定制的调度算法
缺点:
如果发送I/O或页面故障引起的堵塞,内核由于不知道多线程的存在,会阻塞整个进程从而阻塞所有线程
在内核空间实现线程
特点:当某个线程希望创建或撤销一个线程时,它会进行一个系统调用,这个系统调用通过对线程表的更新完成创建或销毁工作
优点:
1、所有能够阻塞线程的调用都以系统调用的形式实现
2、如果某个线程引起了页面故障,内核可以很方便地检查该进程是否有任何其他可运行的线程
混合实现
在这种模型下,内核线程可以被多个用户级线程多路复用。内核只认内核级线程,并对其调度。
进程间通信
这个也是很重点,兄弟们
进程间通信机制大概分为6种:
- 信号
- 套接字
- 消息队列
- 先入先出队列
- 共享内存
- 管道
信号
信号可以在任何时候发送给某一个进程。
进程可以选择忽略,阻塞信号。有两个是不能忽略的,SIGSTOP、SIGKILL。阻塞信号是延迟信号,等到想处理信号再处理信号。
例如Crtl + C就是产生中断信号。
管道
管道允许进程之间按先进先出的方式传送数据。
- 管道是半双工通信,数据只能向一个方向流动
- 匿名管道只能用于父子或兄弟进程
- 单独构成一个独立的文件系统。只存在再内存中
共享内存
共享内存允许两个或多个进程共享一个给定的存储区,这一段存储区可以被两个或多个映射至自身的地址空间中,一个进程写入信息至共享区,可以被其他进程读取,实现通信。
采用共享内存进行通信的一个好处就是效率高,因为进程可以直接读取内存,不需要对任何数据拷贝。
一般而言,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时在重新建立共享内存区域;而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回文件,因此,采用共享内存的通信方式效率非常高。
共享内存有两种实现方式:内存映射和共享内存机制
先入先出队列
就是命名管道,和匿名管道的区别就在与,可以任意进程进行通信,具有支持文件和独特API,命名管道会保留再文件系统,任何进程都可以访问。
消息队列
消息队列,就是一个消息的链表,是一系列保存在内核中消息的列表。用户进程可以向消息队列添加消息,也可以向消息队列读取消息。
消息队列与管道通信相比,其优势是对每个消息指定特定的消息类型,接收的时候不需要按照队列次序,而是可以根据自定义条件接收特定类型的消息。
可以把消息看做一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息,对消息队列有读权限的进程可以从消息队列中读取消息。
套接字
socket提供端到端的双相通信。一个套接字可以和一个或多个进程关联。套接字一般用于进程间的网络通信,需要来自TCP或UDP等基础协议的支持。
- 顺序包套接字(Sequential PacketSocket):此类套接字为最大长度固定的数据报提供可靠的连接。此连接是双向的并且是顺序的。
- 数据报套接字(DatagramSocket):数据包套接字支持双向数据流。数据包套接字接受消息的顺序与发送者可能不同。
- 流式套接字(StreamSocket):流套接字的工作方式类似于电话对话,提供双向可靠的数据流。
- 原始套接字(RawSocket):可以使用原始套接字访问基础通信协议。
详细通信细节可参考:
进程间通信