面试题答案
一键面试上下文切换发生过程
- 线程调度时机:当一个线程的时间片用完、主动调用阻塞函数(如
sleep
、read
等)、被更高优先级线程抢占,系统会触发线程调度,从而发生上下文切换。 - 保存当前线程上下文:内核会将当前运行线程的CPU寄存器(如通用寄存器、程序计数器
PC
、栈指针SP
等)的值保存到该线程对应的内核栈中。这些寄存器保存了线程运行的当前状态和执行位置等关键信息。 - 选择新线程:调度器根据调度算法(如CFS等)从就绪队列中选择一个新的线程来运行。
- 恢复新线程上下文:内核从新线程的内核栈中读取之前保存的CPU寄存器值,加载到CPU的对应寄存器中,使得CPU能够从新线程上次中断的位置继续执行。
关键数据结构
task_struct
:这是内核中描述进程(线程在Linux下也是用进程相关结构来管理,通过共享某些资源来实现线程概念)的基本数据结构。其中包含了线程的状态、调度相关信息、打开的文件描述符表、内存映射信息以及指向内核栈的指针等。对于线程,还会有指向所属进程(线程组)的指针等特殊信息。- 内核栈:每个线程都有自己独立的内核栈,用于保存线程在内核态运行时的函数调用栈以及上述提到的上下文切换时保存的CPU寄存器值。
- 就绪队列:这是一个数据结构(通常是链表或优先级队列),用于存放处于就绪状态(可运行但尚未获得CPU资源)的线程。调度器从这个队列中选择下一个要运行的线程。
系统调用
在C语言创建线程时,一般使用POSIX线程库(pthread
),其底层会涉及以下系统调用:
clone
:pthread_create
函数底层通常会调用clone
系统调用。clone
系统调用可以创建一个新的轻量级进程(线程)。它可以指定新线程与父线程共享的资源(如地址空间、文件描述符等),同时在内核中为新线程创建task_struct
等数据结构,并分配内核栈等资源。新线程创建后就会进入就绪队列等待调度,进而在合适的时候发生上下文切换开始运行。