进程、线程、协程的区别

简介: 进程、线程、协程的区别

进程

进程是操作系统进行资源分配和调度的基本单位。

进程,一个启动的程序, 进程占用的是系统资源,如:物理内存,CPU,终端等,是一个动态的概念。

每个进程在内核中都有一个进程控制块(PCB)来维护进程相关的信息,Linux内核的进程控制块是task_struct结构体。


线程

线程是操作系统调度的最小单位。

线程又叫轻量级的进程(LWP:light weight process)

  • 进程:拥有独立的地址空间,拥有PCB,相当于独居。
  • 线程:有PCB,但没有独立的地址空间,多个线程共享进程空间,相当于合租。


上述说线程有PCB的原因:有资料说

Linux内核线程实现原理

类Unix系统中,早期是没有“线程”概念的,80年代才引入,借助进程机制实现出了线程的概念。因此在这类系统中,进程和线程关系密切。

轻量级进程(light-weight process),也有PCB,创建线程使用的底层函数和进程一样,都是clone

从内核里看进程和线程是一样的,都有各自不同的PCB,但是PCB中指向内存资源的三级页表是相同的

进程可以蜕变成线程

线程可看做寄存器和栈的集合

在linux下,线程最是小的执行单位;进程是最小的分配资源单位

察看LWP号:ps –Lf pid 查看指定线程的lwp号。

三级映射:进程PCB --> 页目录(可看成数组,首地址位于PCB中) --> 页表 --> 物理页面 --> 内存单元

参考:《Linux内核源代码情景分析》 ----毛德操

对于进程来说,相同的地址(同一个虚拟地址)在不同的进程中,反复使用而不冲突。原因是他们虽虚拟址一样,但,页目录、页表、物理页面各不相同。相同的虚拟址,映射到不同的物理页面内存单元,最终访问不同的物理页面。

但!线程不同!两个线程具有各自独立的PCB,但共享同一个页目录,也就共享同一个页表和物理页面。所以两个PCB共享一个地址空间。

实际上,无论是创建进程的fork,还是创建线程的pthread_create,底层实现都是调用同一个内核函数clone。

如果复制对方的地址空间,那么就产出一个“进程”;如果共享对方的地址空间,就产生一个“线程”。

因此:Linux内核是不区分进程和线程的。只在用户层面上进行区分。所以,线程所有操作函数 pthread_* 是库函数,而非系统调用。

也有别的资料说,线程有PCB,不是单独的一个进程,我更偏向第一种说明,这里第二种资料就不展开了。

线程共享资源:

  • 文件描述符表
  • 每种信号的处理方式sigaction
  • 当前工作目录
  • 用户ID和组ID
  • 内存地址空间 (.text/.data/.bss/heap/共享库)

线程非共享资源:

  • 线程id
  • 处理器现场和栈指针(内核栈)
  • 独立的栈空间(用户空间栈)
  • errno变量
  • 信号屏蔽字
  • 调度优先级

多线程中的信号处理

协程

协程的思想很早就被提出来了,最初是为了解决编译器实现中的问题,后来相继出现了很多种实现方式,例如windows中的纤程,再例如lua中coroutine,由于go原生支持协程,所以以下介绍皆是围绕go协程展开。


线程是进程中的执行体,拥有一个执行入口,以及从进程虚拟地址空间中分配的栈(用户栈和内核栈),操作系统会记录线程控制信息,而线程获得CPU时间片以后才可以执行,CPU这里栈指针,指令指针,栈基等寄存器都要切换到对应的线程。如果线程自己又创建了几个执行体(协程),给它们各自指定执行入口,申请一些内存分给它们用作执行栈,那么线程就可以按需调度这几个执行体了。为了实现这些执行体的切换,线程也需要记录它们的控制信息。包括ID,执行栈的位置,执行入口地址,执行现场等等。线程可以选择一个执行体来执行,此时CPU中指令指针就会指向这个执行体的执行入口,栈基和栈指针寄存器也会指向线程给它分配的执行栈。要切换执行体时,需要先保存当前执行体的执行现场,然后切换到另一个执行体。通过同样的方式,可以恢复到之前的执行体, 这样就可以从上次中断的地方继续执行。这些由线程创建的执行体就是所谓的“携程”。因为用户程序不能操作内核空间,所以只能给协程分配用户栈,而操作系统对协程一无所知,所以协程又被称为“用户态线程”。

上图是GMP模型,M是内核线程,对内核而言,它执行什么,全权由P调度器进行调度,G是协程,操作系统对用户态协程一无所知。协程整体对内核保持一个线程的形态,而局部对用户态来说,分成了多个协程。

深入理解GMP模型

协程和IO多路复用

目录
相关文章
|
1月前
|
调度 开发者 Python
深入浅出操作系统:进程与线程的奥秘
在数字世界的底层,操作系统扮演着不可或缺的角色。它如同一位高效的管家,协调和控制着计算机硬件与软件资源。本文将拨开迷雾,深入探索操作系统中两个核心概念——进程与线程。我们将从它们的诞生谈起,逐步剖析它们的本质、区别以及如何影响我们日常使用的应用程序性能。通过简单的比喻,我们将理解这些看似抽象的概念,并学会如何在编程实践中高效利用进程与线程。准备好跟随我一起,揭开操作系统的神秘面纱,让我们的代码运行得更加流畅吧!
|
1月前
|
消息中间件 Unix Linux
【C语言】进程和线程详解
在现代操作系统中,进程和线程是实现并发执行的两种主要方式。理解它们的区别和各自的应用场景对于编写高效的并发程序至关重要。
62 6
|
1月前
|
调度 开发者
深入理解:进程与线程的本质差异
在操作系统和计算机编程领域,进程和线程是两个核心概念。它们在程序执行和资源管理中扮演着至关重要的角色。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
63 5
|
1月前
|
算法 调度 开发者
深入理解操作系统:进程与线程的管理
在数字世界的复杂编织中,操作系统如同一位精明的指挥家,协调着每一个音符的奏响。本篇文章将带领读者穿越操作系统的幕后,探索进程与线程管理的奥秘。从进程的诞生到线程的舞蹈,我们将一起见证这场微观世界的华丽变奏。通过深入浅出的解释和生动的比喻,本文旨在揭示操作系统如何高效地处理多任务,确保系统的稳定性和效率。让我们一起跟随代码的步伐,走进操作系统的内心世界。
|
1月前
|
调度 开发者
核心概念解析:进程与线程的对比分析
在操作系统和计算机编程领域,进程和线程是两个基本而核心的概念。它们是程序执行和资源管理的基础,但它们之间存在显著的差异。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
60 4
|
7月前
|
监控 Linux 应用服务中间件
探索Linux中的`ps`命令:进程监控与分析的利器
探索Linux中的`ps`命令:进程监控与分析的利器
146 13
|
6月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
|
6月前
|
弹性计算 Linux 区块链
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
203 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
|
5月前
|
算法 Linux 调度
探索进程调度:Linux内核中的完全公平调度器
【8月更文挑战第2天】在操作系统的心脏——内核中,进程调度算法扮演着至关重要的角色。本文将深入探讨Linux内核中的完全公平调度器(Completely Fair Scheduler, CFS),一个旨在提供公平时间分配给所有进程的调度器。我们将通过代码示例,理解CFS如何管理运行队列、选择下一个运行进程以及如何对实时负载进行响应。文章将揭示CFS的设计哲学,并展示其如何在现代多任务计算环境中实现高效的资源分配。
|
6月前
|
存储 缓存 安全
【Linux】冯诺依曼体系结构与操作系统及其进程
【Linux】冯诺依曼体系结构与操作系统及其进程
186 1