进程、线程和协程详解


前言

本篇文章记录的是在学习操作系统的过程中的一些总结和笔记,本篇重点讲解进程、线程和协程的概念,以及三者之间的关系等等。


提示:以下是本篇文章正文内容,下面案例可供参考

一、进程是什么?

为了在讨论进程之前对其有一个大概的了解,首先不可避免的一个话题就是操作系统,我们都知道,现代的计算机软件都是基于操作系统之上来运行的,操作系统封装了计算机底层的硬件资源(如键盘、显示器、磁盘或主存等),当我们的应用程序想要访问和使用这些计算机资源的时候,唯一的方式就是依靠操作系统提供的服务(系统调用),进而在计算机硬件资源、操作系统以及应用程序之间有以下的一种关系

计算机硬件资源、操作系统以及应用程序之间的关系
操作系统通过几个基本的抽象概念(进程、虚拟内存和文件)来实现两个基本的功能:1)防止硬件被失控的应用程序滥用,2)向应用程序提供简单一致的机制来控制复杂而又大不相同的低级硬件设备。从宏观的角度来讲,文件是对IO设备的抽象,虚拟内存是对主存和磁盘IO设备的抽象,进程则是对处理器、主存和IO设备的抽象表示。下面我们重点讨论进程的概念,另外两个其他的概念以后再讨论。

进程

在程序运行的时候,操作系统提供了一种假象,使得程序认为自己是独占整个系统资源的(处理器、主存和IO设备),这种假象是通过进程来实现的。当然,进程的定义各说纷云,本质上来说,进程是操作系统对一个正在运行的程序的一种抽象。一个系统里面可以同时运行多个进程,而每一个进程又好像是在独占的使用硬件资源,这是通过处理器在进程之间不停的切换来实现的。操作系统实现这种交错运行的机制称为上下文切换。这里在另外的补充一点,进程之间的切换是有操作系统内核管理的,而内核就是操作系统的核心代码,常驻在主存部分。进程的抽象概念在代码实现中是使用进程控制块(PCB)来实现的,在内核代码中就是一个包含了进程运行时的各种数据的结构体(task_struct)。
这里在结合上面说到的系统调用(system call)来做一个整体的总结,当应用程序需要操作系统的某些操作的时候,他就会执行一条特殊的系统调用指令,将控制权传递给内核(有用户态转为内核态),然后内核执行被请求的操作并且返回给应用程序。

知识小点

Linux理论上可以创建多少个进程?
我们知道,每一个进程都有一个进程标识符(pid),而一般的Linux系统都是使用pid_t的类型来表示pid变量的,而pid_t类型一般都是int类型的,因此,最大的进程数量取决于pid_t变量的最大值。当然凡事都不会有绝对的,也可以通过系统配置文件来进行修改这个值的上限

二、线程

相比于进程来说,线程的概念就相对而言简单一些。一般来说,进程是系统资源分配和调度的基本单位,线程是处理器(CPU)资源分配和调度的基本单位。通常情况下,一个进程里面只有一个控制流,但是在现代的系统中,为了充分的利用系统资源,一个进程实际上是可以有多个称为线程的执行单元的,每一个线程都运行在进程的上下文(进程地址空间)中,一个进程中的线程除了自己独有的数据之外,都是共享同一个进程里面的数据的,故在多线程之间共享数据比在多进程之间共享数据容易很多。进程在实现上有分为内核级线程和用户级线程,以及内核级和用户级混合的线程。在Linux系统中,是没有真正意义上的线程的,它将线程的实现为一个轻量级的进程,其通过在进程之间共享数据的方式来实现线程的。相对于Linux系统的其他系统,比如windows系统就实现了区别于进程的线程。

知识小点

进程和线程的区别和联系
区别如下:

  • 进程是对运行时程序的封装,是系统进行资源分配和调度的基本单元,而线程是进程的子任务,是处理器(CPU)分配和调度的基本单元。
  • 一个进程可以有多个线程,但是一个线程只能属于一个进程。
  • 进程的创建需要系统分配内存和CPU,文件句柄等资源,销毁时也要进行相应的回收,所以进程的管理开销很大;但是线程的管理开销则很小。
  • 进程之间不会相互影响;而一个线程崩溃可能会导致进程崩溃,从而影响同个进程里面的其他线程。
  • 进程使用fork或者vfork来创建,而线程使用pthread_create来创建

联系如下:
进程与线程之间的关系:线程是存在进程的内部,一个进程中可以有多个线程,一个线程只能存在一个进程中。

进程之间私有和共享的资源:

  • 私有:地址空间、堆、全局变量、栈、寄存器
  • 共享:代码段,公共数据,进程目录,进程 ID

线程之间私有和共享的资源:

  • 私有:线程栈,寄存器,程序计数器
  • 共享:堆,地址空间,全局变量,全局静态变量

三、进程间的通信(IPC)

进程之间的通信方式主要有六种:管道、信号量、消息队列、信号、共享内存和套接字,下面从数据共享和状态同步开始来依次讲解各个通信方式。

临界区

资源的共享会造成数据的竞争问题,为了避免这种竞争问题的方式就是禁止多个进程在同一时刻对共享资源进行读写操作。也就是说,我们需要一种可以阻止多个进程同时去读写共享资源,最简单的实现方式就是使用互斥条件,此方式可以保证多个进程不会同时去读写共享资源。

为了讨论的方便,人为的把对共享内存进行访问的程序片段称作临界区域(critical region)或临界区(critical section)。只要保证使得不同的进程不能同时处于临界区,即可避免数据竞争问题。

尽管临界区的设计避免了竞争问题,但是不能确保并发线程同时访问共享数据的正确性和高效性,因此,进一步抽象得到一个好的解决方案应该包含以下必要条件:

  • 任何时候两个进程不能同时处于临界区
  • 不应对 CPU 的速度和数量做任何假设
  • 位于临界区外的进程不得阻塞其他进程
  • 不能使任何进程无限等待进入临界区

忙等互斥

在上一小节讨论了实现临界区的方案是使用互斥,本节讨论实现互斥的各种方案,在这些方案中,当一个进程正忙于更新其临界区的共享内存的时候,保证了没有其他进程会进入临界区。

屏蔽中断

最简单的实现方案是屏蔽中断,在进程进入到临界区的时候立刻屏蔽中断,在离开临界区的时候再重启。因为屏蔽中断后,系统的时钟中断也会被屏蔽掉,而CPU只会在发生时钟中断或其他系统中断的时候才会进行进程间的切换,这样就导致了CPU不会切换到其他的进程去执行,只会执行当前的进程。

上述方案存在的一个问题是,如果经过长时间的执行后,进程仍然没有离开临界区,那么系统中断就一直启动不了,如果此时是单处理器系统,那么整个系统就会终止服务,进而违反了在上一节提到的条件–不能使任何进程无限等待进入临界区。如果是多处理器的话,屏蔽中断仅仅对执行disable指令的C

  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值