【面试题】操作系统面试题(第四篇)

1.进程的概念

进程的概念在计算机科学中,是指一个具有一定独立功能的程序关于某个数据集合上的一次运行活动,也是系统进行资源分配和调度的基本单位,是操作系统结构的基础。

具体来说,进程是操作系统进行资源分配的基本单位,相当于一个程序及其数据在计算机上执行时的一个活动实体。在系统内部看来,进程是内存分配的基本单位,因为系统建立进程的同时,要为它分配内存空间。此外,进程也是“独立运行”“独立分配资源”和“独立调度”的基本单位。

2.进程的种类

1.用户进程:也称为应用进程,是由用户启动的进程来执行应用程序。用户进程是在用户空间中运行的,并且可以与其他用户进程进行通信。

2.系统进程:也称为内核进程,是由操作系统内核启动和管理的进程。

3.孤儿进程:当父进程意外终止或退出时,子进程可能成为孤儿进程。孤儿进程将由操作系统接管,并由操作系统中的一个特殊进程(通常是init进程)接收和回收。

4.守护进程:是在后台运行的进程,独立于用户会话的一种特殊进程。守护进程通常在系统启动时启动,并持续运行,提供系统服务或执行特定的任务(特殊的孤儿进程)。

5.僵尸进程:当子进程完成执行(终止)后,但父进程尚未调用wait()或waitpid()来获取子进程的退出状态码时,子进程将成为僵尸进程。僵尸进程仍保留在进程表中,但不再执行任何任务。

3.进程虚拟地址空间的分布情况具体说一下

在 Linux 中,进程的虚拟地址空间通常被分为以下几个部分:

  1. 用户空间(User Space): 用户空间是进程的主要工作区域,用于存放用户应用程序的代码、数据和堆栈。在 32 位系统上,通常是从 0x00000000 到 0xBFFFFFFF(3GB)的范围;在 64 位系统上,用户空间通常是从 0x0000000000000000 到 0x7FFFFFFFFFFFFFFF(128TB)的范围。

  2. 内核空间(Kernel Space): 内核空间用于存放操作系统内核的代码和数据结构。在 32 位系统上,通常是从 0xC0000000 到 0xFFFFFFFF 的范围;在 64 位系统上,内核空间通常是从 0xFFFF800000000000 到 0xFFFFFFFFFFFFFFFF 的范围。

  3. 共享库区域(Shared Libraries Region): 存放共享库(动态链接库)的代码和数据,通常在用户空间的某个位置,由动态链接器进行加载。

  4. 栈(Stack): 用于存放函数调用的局部变量和函数调用的上下文信息,通常位于用户空间的底部。

  5. 堆(Heap): 用于动态分配内存,通常位于用户空间的较低部分。

  6. 内存映射区域(Memory-Mapped Regions): 用于将文件或设备映射到进程的地址空间,包括映射文件、共享内存等。

  7. 栈区域(Stack Area): 用于存放线程的栈,通常位于用户空间。

  8. VDSO(Virtual Dynamic Shared Object): 用于存放一些内核提供的函数,以用户态方式调用内核功能。

  9. Vsyscall: 用于存放一些系统调用,以用户态方式调用内核功能。

4.线程的概念

定义:线程(英语:thread)是操作系统能够进行运算调度的最小单位。它包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

5.线程的种类

1.用户线程

  • 用户线程完全由用户空间的应用程序进行管理和调度,操作系统对其无感知。

  • 用户线程的创建、调度和管理都由应用程序自己负责。

  • 用户级线程一般在用户层实现,用户层访问,用户层切换, 大大减少了用户层切换到内核的次数, 降低系统开销,提高处理速度。

  • 用户线程的优点在于灵活、轻量级,但也存在局限性,同一时间只有一个线程可以运行,当一个线程被阻塞时,所有线程都被阻塞。

2.内核线程

  • 内核线程是由操作系统内核直接创建、调度和管理的线程。

  • 内核线程的创建和切换开销相对较高,在操作系统层级上实现了多线程的调度和管理。

  • 内核线程遵循操作系统的调度策略,可以更好地利用多核处理器,并允许并行执行。

  • 内核线程的优点在于稳定性、可靠性和多核利用,但开销相对较高。

3.混合线程

  • 混合型线程是用户线程和内核线程的结合体,将二者相结合以兼顾灵活性和性能。

  • 在混合型线程模型中,用户线程由应用程序创建和管理,但其底层支持由内核线程提供。

  • 用户线程在用户空间中运行,操作系统将其映射到内核线程上,由内核线程实际执行。

  • 混合型线程可以通过底层的内核线程来实现并发性和并行性,同时在用户空间具有较低的调度和切换开销。

6.协程

协程(Coroutine)是一种用户态的轻量级线程,其执行可以在任何一点被挂起并恢复,允许程序在单线程内实现非阻塞或异步的执行。协程不是由操作系统内核来调度和管理的,而是由程序自身来控制。这使得协程的切换开销远小于线程,因此可以创建成千上万的协程而不会导致系统资源的耗尽。

协程的主要特点包括:

  1. 轻量级:协程的创建、销毁和切换的开销很小,远小于线程。这使得可以创建大量的协程来并发执行。

  2. 非抢占式:协程的执行是协作式的,即协程需要显式地让出执行权(yield),以便其他协程可以运行。这与线程的抢占式调度不同。

  3. 共享内存:协程通常在同一线程内执行,因此它们可以共享该线程的内存空间,无需像线程那样进行复杂的同步和通信操作。

  4. 适合I/O密集型任务:由于协程的切换开销小,它们特别适合处理I/O密集型任务,如网络请求、文件读写等。在这些场景中,协程可以避免线程切换和阻塞所带来的性能损失。

  5. 编程模型简单:协程提供了一种直观的编程模型,使得编写并发代码变得更加简单和直观。程序员可以通过协程来组织代码流程,实现异步执行和并发处理。

协程的实现方式有多种,包括使用生成器(Generator)和专门的协程库(如Python的asyncio、Lua的coroutines、Golang的goroutines等)。这些实现方式通常提供了一些关键字或函数来创建、切换和销毁协程。

需要注意的是,虽然协程在某些场景下可以替代线程来提高性能,但它们并不是万能的。对于计算密集型任务或需要并行执行的任务,线程或进程可能仍然是更好的选择。此外,协程的编程模型也需要一定的学习和理解成本。因此,在选择是否使用协程时,需要根据具体的应用场景和需求来权衡利弊。

7.进程和线程区别

进程(Process)是指正在运行的程序实例,它具有独立的内存空间、文件描述符和其他系统资源。每个进程都是独立运行的实体,它们之间相互隔离,互不干扰。进程有自己的程序计数器(记录下一条将要执行的指令)、寄存器集合和堆栈,它们之间共享的只是操作系统提供的资源,如文件、设备等。进程之间通常通过进程间通信(IPC)机制来进行数据交换和同步。

线程(Thread)是进程内的执行单元,它是进程的一个子任务。与进程不同,多个线程可以共享同一进程的内存空间和系统资源,它们可以同时执行,实现并发操作。线程有自己的栈、局部变量和寄存器,但与进程共享全局变量、堆和文件等资源。

  1. 根本区别:进程是操作系统分配资源的基本单位;线程是CPU调度的基本单位。

  2. 地址空间:进程所占地址空间是独立的;线程共享所属进程的地址空间。

  3. 资源开销:进程之间相互隔离,每个进程有独立的内存空间和系统资源,因此创建和销毁进程的开销较大。而线程共享进程的资源,创建和销毁线程的开销较小。

  4. 稳定性:进程之间相互隔离,一个进程的崩溃不会影响其他进程。而线程共享进程的资源,一个线程的错误可能导致整个进程崩溃。

  5. 上下文切换:进程切换速度比线程慢很多。

8.协程和线程区别?

协程是用户态的轻量级线程,线程内部调度的基本单位。

协程和线程都是用于实现多任务的技术,但是它们的实现方式有所不同,具体区别如下:

  • 调度方式不同:线程由操作系统内核进行调度,而协程则是在用户空间中由用户进行调度,不需要切换到内核态。

  • 并发性不同:线程是操作系统调度的最小单位,多个线程可以并行执行;协程则是在同一时间只能执行一个协程。

  • 内存使用不同:线程是由操作系统内核创建的,需要占用一定的系统资源,而协程则是由用户程序创建,不需要占用额外的系统资源。

  • 上下文切换开销不同:线程在切换时需要保存和恢复所有的寄存器状态和内核堆栈,而协程只需要保存和恢复少量的寄存器状态,开销较小。

总之,线程是操作系统内核的调度对象,具有独立的系统资源,可以并行执行多个任务;而协程是用户程序的调度对象,不需要占用额外的系统资源,通过协作式调度实现任务之间的切换

9.为什么线程切换比进程快

  1. 资源共享:线程是在同一个进程内创建的,它们共享相同的地址空间、文件描述符和其他资源。因此,在进行线程上下文切换时,不需要切换地址空间和资源的分配,这使得线程上下文切换比进程上下文切换更快。

  2. 上下文切换开销较小:换入/换出的页表更小。进程切换需要切换整个进程的虚拟内存空间,而线程切换只需要切换自己的栈和寄存器状态。

  3. 线程调度开销小:由于线程是在同一个进程中运行的,因此线程调度不涉及进程调度的复杂逻辑。当进行线程切换时,仅需要切换线程的上下文,而不需要改变进程的状态。

  4. 缓存局部性:线程在同一进程内,它们更有可能访问相同的数据和代码。当进行线程切换时,由于缓存中可能已经存在该线程所需的数据和指令,所以缓存命中率更高,减少了内存访问开销。

10.线程间共享和非共享资源

共享资源:全局变量、静态变量、堆内存、文件描述符、信号行为等。

非共享资源:线程栈、程序计数器(存放下一个指令的地址)、寄存器、信号屏蔽字、线程信息TID、线程优先级、ERRNO全局变量等。

11.线程有哪些属性

  1. 标识符(ID):线程的唯一标识符,用于区分不同的线程。

  2. 线程优先级:表示线程获取CPU资源的优先级,使用优先级调度算法。

  3. 调度策略:指定线程被调度的方式,例如先进先出(FIFO)、抢占式等。

  4. 栈大小:线程所使用的栈的大小,用于存储局部变量和函数调用信息。

  5. 终止状态:标志线程是否已经终止或退出。

  6. 线程上下文:保存线程执行时的寄存器和状态信息。

  7. 线程状态:表示线程的当前状态,如运行、就绪、阻塞等。

  8. 线程组:将线程组织成一个组,并对组内的线程进行管理。

  9. 守护线程:表示该线程是否为守护线程,即在主线程退出时是否自动结束。

  10. 线程名称:为了方便标识和调试,可以为线程指定一个名称。

其中某些属性可以自定义设置。

12.线程的内核栈是共享还是独栈,程序确定它的位置?

在多线程环境中,每个线程通常都有自己独立的内核栈,这些内核栈是线程私有的,不与其他线程共享。每个线程的内核栈用于存储线程在内核模式下执行时的上下文信息,如函数调用、局部变量等。

线程的用户栈(用户态栈)也是独立的,用于存储线程在用户模式下执行时的函数调用和局部变量。与内核栈不同,用户栈是线程的用户态代码和数据使用的栈。

程序通常不需要显式确定线程的内核栈的位置。操作系统负责为每个线程分配内核栈,并在线程创建时进行设置。内核栈的大小和位置由操作系统决定,并通常存储在线程的控制块(Thread Control Block,TCB)中,以便操作系统在需要时可以访问。

13.请详述一下线程栈

线程栈确实可以分为用户栈和内核栈。以下是关于用户栈和内核栈的详细解释:

  1. 用户栈:

    • 用户栈是用户进程空间中的一块区域,主要用于保存用户进程的子程序间相互调用的参数、返回值、返回点以及子程序(函数)的局部变量。

    • 当进程在用户空间运行时,CPU堆栈指针寄存器的内容是用户栈的地址,此时使用的是用户栈。

    • 用户栈是进程地址空间的一部分,每个进程都有自己独立的用户栈。

  2. 内核栈:

    • 内核栈是执行操作系统内核功能时使用的位于内核地址空间中的栈。

    • 当进程在内核空间运行时,CPU堆栈指针寄存器的内容是内核栈的地址,此时使用的是内核栈。

    • 内核栈与进程是绑定的,每个进程都会有一个与之关联的内核栈,用于在内核态执行代码时保存内核的局部变量和调用栈信息。

用户栈与内核栈的转换

  • 当进程中发生系统调用或者中断时,进程所使用的堆栈会从用户栈转到内核栈。进程进入内核栈后,先把用户栈的地址保存在内核栈中,然后设置CPU堆栈指针寄存器的内容为内核栈地址,这样就完成了用户栈向内核栈的转换。

  • 当进程从内核态恢复到用户态后,先把内核栈中保存的用户栈地址设置到CPU堆栈指针寄存器即可,这样就完成了内核栈向用户栈的转换。

总结来说,用户栈和内核栈是线程栈的两个主要组成部分,分别用于在用户空间和内核空间保存线程的执行上下文信息。在用户空间和内核空间切换时,线程栈会在用户栈和内核栈之间进行转换。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

爱编程的小猴

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

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

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

打赏作者

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

抵扣说明:

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

余额充值