进程
狭义理解就是操作系统中一段程序的执行过程。
那么广义上,进程是指一个具有一定独立功能的程序操作系统中关于某个数据集合进行的一次运行活动。
是操作系统程序动态执行的基本单元。在传统的操作系统中,进程既是一个操作系统的基本分配单元,也是操作系统的基本执行单元。
进程的状态
进程共有三种状态:就绪、阻塞和运行
- 就绪态
就绪状态是指程序已达到可以运行的状态,只等CPU分配资源就可以运行的状态。
- 阻塞态
当程序运行条件没有满足时,需要等待条件满足时候才能执行时所处的状态,如等待i/o操作时候,此刻的状态就叫阻塞态。
- 运行态
进程占用CPU,并在CPU上运行。即程序正在运行时所处的状态。
PCB(Process Control Block,进程控制块)
在 Linux 中,每个进程都有一个 PCB,它存储了关于该进程的所有信息,包括进程的状态、进程 ID、进程的优先级、进程的内存映像、打开的文件、进程的父进程和子进程等等。PCB 可以用来管理进程,使操作系统能够对进程进行调度和管理。
PCB 在 Linux 中是一个数据结构,通常被表示为 task_struct 类型的变量。每个进程都有一个唯一的 task_struct 变量来表示它的 PCB。当一个进程被创建时,操作系统会为它分配一个 task_struct 变量,并在进程执行期间更新它的信息。
- PCB(Process Control Block,进程控制块): PCB是操作系统用来表示进程的数据结构,包含一个进程的所有状态信息。通常包括以下部分:
- 进程标识符:用于唯一标识一个进程
- 处理器状态信息:包括程序计数器、寄存器、堆栈指针等,用于表示进程在CPU上的执行状态
- 进程调度信息:包括进程优先级、状态(运行、就绪、阻塞等)、调度策略等,用于操作系统调度进程
- 内存管理信息:包括进程的地址空间、页表等,用于描述进程在内存中的布局
- 资源管理信息:包括打开的文件描述符、信号量、消息队列等,用于管理进程所使用的系统资源
- 其他信息:如进程创建时间、执行时间、进程间通信信息等
线程
线程是进程中执行运算的最小单元,是操作系统执行处理机制的基本单位。
每个进程至少有一个线程,线程可以利用进程所拥有的资源执行调度和运算。
进程与线程
轻量级进程(light-weight process),也有 PCB( Process Control Block),创建线程使用的底层函数和进程一样,都是clone。
从内核里看进程和线程是一样的,都有各自不同的PCB,但是PCB中指向内存资源的三级页表是相同的。三级映射:进程PCB --> 页目录(可看成数组,首地址位于PCB中) --> 页表 --> 物理页面 --> 内存单元
关于线程的阻塞和进程的退出
进程的上下文切换和退出等都依赖于内核.
如果进程在用户态阻塞,无法进入内核态,那么调用
exit()
来退出进程将无法执行。当进程陷入无法响应的状态时,这种情况可能发生。例如,进程可能因为死锁、资源竞争、I/O阻塞等原因而无法继续执行。在这种情况下,进程无法主动退出,因为它不能调用
exit()
来触发内核态的切换和进程终止。然而,外部程序或者系统管理员可以通过向进程发送信号(如SIGKILL
或SIGTERM
)来强制终止进程。信号处理是由内核完成的,这将使进程切换到内核态并执行终止操作。需要注意的是,发送
SIGKILL
信号将立即终止进程,不会执行任何清理操作,可能导致数据丢失或资源泄露。而发送SIGTERM
信号通常会让进程执行清理操作,然后终止。但是,如果进程因为阻塞而无法执行信号处理程序,那么SIGTERM
信号可能无法成功终止进程。在这种情况下,SIGKILL
信号可能是唯一的选择。如果进程在用户态阻塞,无法进入内核态,那么调用
exit()
来退出进程将无法执行。当进程陷入无法响应的状态时,这种情况可能发生。例如,进程可能因为死锁、资源竞争、I/O阻塞等原因而无法继续执行。在这种情况下,进程无法主动退出,因为它不能调用
exit()
来触发内核态的切换和进程终止。然而,外部程序或者系统管理员可以通过向进程发送信号(如SIGKILL
或SIGTERM
)来强制终止进程。信号处理是由内核完成的,这将使进程切换到内核态并执行终止操作。需要注意的是,发送
SIGKILL
信号将立即终止进程,不会执行任何清理操作,可能导致数据丢失或资源泄露。而发送SIGTERM
信号通常会让进程执行清理操作,然后终止。但是,如果进程因为阻塞而无法执行信号处理程序,那么SIGTERM
信号可能无法成功终止进程。在这种情况下,SIGKILL
信号可能是唯一的选择。当进程退出时,如果写入文件的内容仍然保存在缓冲区中,尚未同步到文件中,那么程序异常退出可能会导致文件内容无法正确同步。
正常情况下,在进程退出时,会执行清理操作,包括将缓冲区中的数据刷新到磁盘。但是,当程序异常退出(如因为段错误、异常信号等)时,这些清理操作可能无法执行。这可能导致缓冲区中的数据丢失,无法正确写入文件。
为了降低这种风险,可以在写入文件后显式地调用
fsync()
(针对文件描述符)或fflush()
(针对FILE*
流)函数,以确保缓冲区中的数据被刷新到磁盘。这样即使程序异常退出,之前刷新到磁盘的数据仍然是安全的。但请注意,频繁调用这些函数可能会影响I/O性能。另外,如果进程异常退出,操作系统可能会尝试进行一定程度的清理工作,包括关闭文件描述符等。但这种清理可能不如正常退出时的清理完善,因此不能完全依赖于操作系统来确保数据的完整性。
进程/线程的调度
进程退出的回收机制
进程与线程的对比
- 进程是操作系统资源分配的基本单位,所有与该进程有关的资源,均会被记录在进程控制块PCB中,以表示该进程所拥有的资源。同一进程下的所有线程共享该进程下的所有资源。
- 线程是分配处理机的基本单位,与系统资源分配无关。事实上,正在在处理机上运行的是线程,并非进程。
- 一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
- 线程在执行的时候需要协作同步,不同进程的线程间要利用消息通信方法实现同步。
- 在linux下,线程最是小的执行单位;进程是最小的分配资源单位.
进程与线程的关系
- 进程将CPU资源分给线程,即真正在CPU上运行的是线程。
- 操作资源分配给进程,同一进程的所有线程共享该进程的所有资源。
进程与线程的区别
- 同一个进程中的线程共享同一内存空间,但是进程之间是独立的。
- 同一个进程中的所有线程的数据是共享的(进程通讯),进程之间的数据是独立的。
- 对主线程的修改可能会影响其他线程的行为,但是父进程的修改(除了删除以外)不会影响其他子进程。
- 线程是一个上下文的执行指令,而进程则是与运算相关的一簇资源。
- 一个线程可以操作同一进程的其他线程,但是进程只能操作其子进程。
多进程
在同一个时间里,同一个计算机系统中如果允许两个或两个以上的进程处于运行状态,这便是多任务(多进程)。
现代的操作系统几乎都是多进程操作系统,能够同时管理多个进程的运行。 多进程带来的好处是明显的。
但是多进程对于系统的资源要求甚高,资源浪费也比较严重。应用多进程场景最多的是windows系统,例如同时打开运行软件,每个软件打开相当于运行一个进程。
多线程
在一段完整的代码中,往往会有需要独立的代码模块,而这些独立运行的程序片段叫作“线程”(Thread),
利用多个线程编程的概念就叫作多线程处理(多线程编程),多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。
多线程是在程序在同一时间需要完成多项任务的时候实现的。多线程的目的仅仅是为了提高资源利用效率。
各个线程执行自己的任务,这些线程可以”同时进行“。同时进行并非同一时刻进行,而是在某一时间段内,完成所有任务,任务的运行有先后顺序。
并行和并发
在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。
其中两种并发关系分别是同步和互斥。
- 微观角度
所有的并发处理都有排队等候,唤醒,执行等这样的步骤,
在微观上他们都是序列被处理的,如果是同一时刻到达的请求(或线程)也会根据优先级的不同,而先后进入队列排队等候执行。
- 宏观角度
多个几乎同时到达的请求(或线程)在宏观上看就像是同时在被处理。
(并发是指同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上有多个进程被同时执行的效果--宏观上并行,针对单核处理器)
- 并发图示
并发就是只有一个CPU资源,程序(或线程)之间要竞争得到执行机会。
图中的第一个阶段,在A执行的过程中B,C不会执行,因为这段时间内这个CPU资源被A竞争到了,
同理,第二个阶段只有B在执行,第三个阶段只有C在执行。
其实,并发过程中,A,B,C并不是同时在进行的(微观角度)。但又是同时进行的(宏观角度)。
并行(parallelism)
在单处理器中多道程序设计系统中,进程被交替执行,表现出一种并发的外部特种;
在多处理器系统中,进程不仅可以交替执行,而且可以重叠执行。在多处理器上的程序才可实现并行处理。
因此,并行是针对多处理器而言的。并行是同时发生的多个并发事件,具有并发的含义,但并发不一定并行,也亦是说并发事件之间不一定要同一时刻发生。
(同一时刻,有多条指令在多个处理器上同时执行--针对多核处理器)
- 并行图示
同步和异步
进程之间的关系不是相互排斥临界资源的关系,而是相互依赖的关系。
进一步的说明:就是前一个进程的输出作为后一个进程的输入,当第一个进程没有输出时第二个进程必须等待。具有同步关系的一组并发进程相互发送的信息称为消息或事件。
异步和同步是相对的,同步就是顺序执行,执行完一个再执行下一个,需要等待、协调运行。
异步就是彼此独立,在等待某事件的过程中继续做自己的事,不需要等待这一事件完成后再工作。
线程就是实现异步的一个方式。异步是让调用方法的主线程不需要同步等待另一线程的完成,从而可以让主线程干其它的事情。