linux内核进程管理(1)——创建,退出

linux源码阅读——进程管理(1)

  • 1. 进程的基本介绍
    • 1.1 linux中进程和线程的区别
    • 1.2 task_struct中的基本内容
    • 1.3 命名空间ns(namespace)
      • 命名空间结构图
      • Linux 中的命名空间类型
    • 1.4 进程标识符
  • 2. 创建一个进程的流程
    • 2.1 CLONE宏
    • 2.2 创建进程系统调用
      • 1. do_fork流程——v6.9-kernel_clone
      • 2. do_fork中copy_process流程
        • (1). 标志冲突判断
        • (2). dup_task_struct——分配task空间
        • (3). 检查用户的进程数量限制
        • (4). copy_creds复制或共享证书
        • (5). 检查线程数量限制
        • (6). sched_fork——设置调度器相关参数
        • (7). copy_xxx——根据CLONE_FLAG复制或共享资源
      • 3. do_fork中的wake_up_new_task流程
  • 3. 进程的退出
    • 3.1 退出概念简介
    • 3.2 exit_group线程组退出
      • 1. exit_group简介
      • 2. exit_group具体流程
    • 3.3 kill

注 : 图片来自《Linux内核深度解析 基于ARM64架构的Linux 4.x内核》(余华兵)

1. 进程的基本介绍

1.1 linux中进程和线程的区别

在课本教学中我们习惯将进程和线程看作两种差别很大的东西,但是在实际的linux系统中,无论是进程还是线程都由所谓PCB(process control block) 也就是我们的 task_struct表示。

进程的虚拟地址空间分为用户虚拟地址空间和内核虚拟地址空间,所有进程共享内核虚拟地址空间,每个进程有独立的用户虚拟地址空间

  • 先说结论
    • 进程——独立拥有用户虚拟地址空间
    • 用户线程——共享用户虚拟地址空间
    • 内核线程——没有用户虚拟地址空间

那么大家就要问了,什么是用户虚拟地址空间(mm_struct),这个在讲调度的时候介绍
术语约定

1.2 task_struct中的基本内容

成员说明
volatile long state;进程的状态,使用volatile关键字,确保读取都能得到最新的值
void *stack;指向内核栈, 进程在内核态下的运行“装备”,确保进程在进入内核模式时能够正确恢复上下文并安全执行内核代码
pid_t pid;全局的进程号,同一PID命名空间下,pid唯一
pid_t tgid;全局的线程组标识符,在一个多线程进程中,多个线程会有不同的 pid,但它们的 tgid 会相同
struct pid_link pids[PIDTYPE_MAX];进程号,进程组标识符和会话标识符
struct task_struct __rcu *real_parent;real_parent指向真实的父进程, rcu(read-copy-update)并发编程机制
struct task_struct __rcu *parent;parent指向父进程:如果进程被另一个进程(通常是调试器)使用系统调用ptrace跟踪,那么父进程是跟踪进程,否则和real_parent相同
struct task_struct *group_leader;指向线程组的组长
const struct cred __rcu *real_cred;real_cred指向主体和真实客体证书,
const struct cred __rcu *cred;cred指向有效客体证书。通常情况下,cred和real_cred指向相同的证书,但是cred可以被临时改变
char comm[TASK_COMM_LEN];进程名称
int prio, static_prio, normal_prio;
unsigned int rt_priority;
unsigned int policy;
调度策略和优先级,dl,rt,cfs
cpumask_t cpus_allowed允许进程在哪些处理器上运行,处理器亲和性
struct mm_struct *mm,*active_mm;指向内存描述符进程:mm和active_mm指向同一个内存描述符
内核线程:mm是空指针,当内核线程运行时,active_mm指向从进程借用的内存描述符
struct fs_struct *fs;文件系统信息,主要是进程的根目录和当前工作目录
struct files_struct *files;打开文件表
struct nsproxy *nsproxy;命名空间代理
struct signal_struct *signal;
struct sighand_struct *sighand;
sigset_t blocked, real_blocked;
sigset_t saved_sigmask;
struct sigpending pending;
信号处理,
signal_struct 用于存储和管理进程的信号状态。
sighand_struct 管理进程的信号处理程序。
blocked 和 real_blocked 控制进程哪些信号被阻塞,避免信号干扰进程执行。
saved_sigmask 保存和恢复进程的信号掩码状态。
sigpending 存储待处理的信号。

1.3 命名空间ns(namespace)

和虚拟机相比,容器是一种轻量级的虚拟化技术,直接使用宿主机的内核,使用命名空间隔离资源。
命名空间
命名空间(Namespace)是 Linux 内核中的一种重要特性,它用于隔离不同进程的资源,使得多个进程能够在同一台机器上“仿佛”运行在独立的系统中。命名空间技术是实现容器(如 Docker)的核心技术之一。命名空间通过提供资源的隔离,使得不同进程或容器能够有自己独立的资源视图,如进程号(PID)、网络、挂载等。

命名空间结构图

命名空间结构

Linux 中的命名空间类型

Linux 支持多种类型的命名空间,每种命名空间用于隔离系统的某种资源。以下是 Linux 中常见的几种命名空间类型:

  1. 进程号命名空间(PID Namespace)

    • 进程号命名空间使得每个进程可以拥有自己的进程号(PID)。在不同的进程号命名空间中,同一个 PID 号可以表示不同的进程。
    • 父进程的 PID 在子命名空间内不再是唯一的,而是局限于该命名空间中。比如,PID 1 代表的是该命名空间中的第一个进程,而不是宿主机上的第一个进程。
    • 这种隔离有助于容器化应用的管理,因为它们在容器内可以拥有从 1 开始的 PID,而与宿主机的进程号不冲突。
  2. 挂载命名空间(Mount Namespace)

    • 挂载命名空间允许不同的进程在不同的命名空间中看到不同的文件系统视图。
    • 它能够实现容器内进程看到的文件系统与宿主机或其他容器内进程看到的文件系统完全不同。例如,在容器中,你可以挂载不同的目录,而这些挂载操作不会影响宿主机的文件系统。
    • 挂载命名空间是实现文件系统隔离的基础
  3. 网络命名空间(Network Namespace)

    • 网络命名空间提供了进程之间网络资源(如 IP 地址、路由表、网络设备等)的隔离。
    • 每个网络命名空间有自己的网络接口、路由表、防火墙等配置。这样,容器或进程在不同的网络命名空间中,彼此之间不能直接通信,除非通过某种方式显式地配置网络连接。
    • 网络命名空间使得容器能够拥有自己的 IP 地址,甚至在不同的容器之间实现隔离的虚拟网络。
  4. IPC 命名空间(IPC Namespace)

    • IPC 命名空间用于隔离进程间通信(IPC)机制,如信号量、消息队列和共享内存。
    • 在不同的 IPC 命名空间中,进程看到的共享内存段、消息队列等资源是隔离的。即使两个进程有相同的 PID,它们也不能相互访问对方的 IPC 资源。
  5. UTS 命名空间(UTS Namespace)

    • UTS 命名空间用于隔离主机名和域名系统(DNS)信息。
    • 在不同的 UTS 命名空间中,进程可以拥有独立的主机名和域名,进而可以在容器中使用不同的主机名而不影响宿主机。
  6. 用户命名空间(User Namespace)

    • 用户命名空间用于隔离进程的用户和组 ID(UID/GID)。
    • 在一个用户命名空间内,进程可以有一个与宿主机完全不同的 UID 和 GID 映射。例如,容器中的进程可以运行在 UID 0(即 root 用户),而在宿主机上可能对应的是一个普通用户。这使得容器中的进程能够具有 root 权限,但在宿主机上却是以普通用户身份运行,从而提高安全性。
  7. 时间命名空间(Time Namespace)(Linux 5.6 及以后版本)

    • 时间命名空间允许进程有自己独立的时间视图。每个时间命名空间可以有独立的系统时间(即时间和时区设置)。这使得容器能够有自己的时钟和时间管理系统,而不依赖于宿主机的时间。
  8. cgroup 命名空间(Cgroup Namespace)(Linux 4.5 及以后版本)

    • cgroup 命名空间用于隔离进程的控制组(cgroup)信息。cgroup 是一种内核机制,用于对进程进行资源限制、优先级调度等管理。cgroup 命名空间允许每个进程组(如容器)有自己独立的 cgroup 层次结构。

命名空间(Namespace)是 Linux 内核提供的一种资源隔离机制,它通过为进程提供独立的资源视图,确保不同进程或容器之间的隔离。命名空间的类型包括 PID、网络、挂载、IPC、UTS、用户等,这些命名空间在容器化技术、进程管理、安全性等方面起着关键作用。通过使用命名空间,Linux 能够在同一台机器上运行多个互相隔离的进程或容器,从而实现更高效和安全的资源管理。

1.4 进程标识符

  • 进程标识符 pid
  • 线程组标识符 tgid
  • 进程组标识符 pgid
  • 会话标识符 sid
    sid是多个兄弟在一起(shell),pgid是爸爸带一堆儿子(fork)

会话和进程组被设计用来支持 shell 作业控制,shell 为执行单一命令或者管道的进程创建一个进程组

2. 创建一个进程的流程

2.1 CLONE宏

想要了解进程的创建流程首先需要了解,clone都具备哪些标识

标志类别作用
CSIGNAL信号相关标志子进程退出时发送给父进程的信号掩码。
CLONE_VM资源共享标志父子进程共享虚拟内存空间,通常用于线程。
CLONE_FS资源共享标志父子进程共享文件系统信息(如当前工作目录、根目录等)。
CLONE_FILES资源共享标志父子进程共享打开的文件描述符。
CLONE_SIGHAND资源共享标志父子进程共享信号处理程序和阻塞信号。
CLONE_PIDFD进程级别标志在父进程中为子进程创建一个 pidfd(PID文件描述符)。
CLONE_PTRACE进程级别标志允许追踪继续,父进程可以继续对其子进程进行追踪。
CLONE_VFORK进程级别标志父进程希望子进程在释放其内存时唤醒父进程。
CLONE_PARENT进程级别标志子进程和父进程保持相同的父进程。
CLONE_THREAD线程/进程级别标志子进程和父进程属于同一个线程组,通常用于线程。
CLONE_NEWNS命名空间相关标志创建一个新的挂载命名空间。
CLONE_SYSVSEM进程级别标志父子进程共享 System V 信号量(SEM_UNDO)语义。
CLONE_SETTLS线程级别标志为子进程创建新的 TLS(线程本地存储)。
CLONE_PARENT_SETTID线程级别标志将线程标识符 (TID) 设置到父进程的 parent_tid 指向的位置。
CLONE_CHILD_CLEARTID线程级别标志线程退出时清除其 TID(线程标识符)。
CLONE_DETACHED进程级别标志已废弃,忽略。
CLONE_UNTRACED进程级别标志如果设置了该标志,父进程不能强制对子进程进行追踪。
CLONE_CHILD_SETTID线程级别标志子进程首次调度时将 TID 设置到 child_tid 指向的位置。
CLONE_NEWCGROUP命名空间相关标志创建一个新的 cgroup(控制组)命名空间。
CLONE_NEWUTS命名空间相关标志创建一个新的 UTS(UNIX时间共享)命名空间,通常用于主机名和域名的隔离。
CLONE_NEWIPC命名空间相关标志创建一个新的 IPC(进程间通信)命名空间。
CLONE_NEWUSER命名空间相关标志创建一个新的用户命名空间,通常用于进程的用户和组 ID 隔离。
CLONE_NEWPID命名空间相关标志创建一个新的 PID(进程标识符)命名空间。
CLONE_NEWNET命名空间相关标志创建一个新的网络命名空间。
CLONE_IO进程级别标志子进程与父进程共享 I/O 上下文(I/O 调度等)。

2.2 创建进程系统调用

(1)fork(分叉):子进程是父进程的一个副本,采用了写时复制的技术。
(2)vfork:用于创建子进程,之后子进程立即调用 execve 以装载新程序的情况。为了避免复制物理页,父进程会睡眠等待子进程装载新程序。现在 fork 采用了写时复制的技术,vfork 失去了速度优势,已经被废弃。
(3)clone(克隆):可以精确地控制子进程和父进程共享哪些资源。这个系统调用的
主要用处是可供 pthread 库用来创建线程。
clone 是功能最齐全的函数,参数多,使用复杂,fork 是 clone 的简化函数。


那么在执行这三个系统调用,实际执行的是do_fork函数,注意在当前(2025/4)最新linux版本6.9中do_fork被更换为kernel_clone(), 具体执行流程和do_fork大体相同,主要变更在kernel_clone 扩展了 do_fork 的功能,并且增加了更多针对不同类型进程创建的支持,特别是在 clone() 调用中引入了更多控制参数和特性。

1. do_fork流程——v6.9-kernel_clone

在v6.9版本的内核中,do_fork被替换取而代之的是kernel_clone,两者核心流程类似
do_fork的流程

  1. 调用函数 copy_process 以创建新进程
  2. 关于第二个步骤中判断CLONE_PARENT_SETTID的操作——CLONE_PARENT_SETTID:这是 clone() 调用中的一个标志,表示 父进程想要在子进程创建时将子进程的 PID 设置到某个指定位置。这个标志位指示内核将子进程的 PID 写入父进程传入的 parent_tid 指针。

具体作用:在一些特定的多线程应用或线程库中,父进程或创建线程的控制者希望在用户空间中直接获得新创建线程(或进程)的 PID,便于后续的管理,比如设置线程的调度策略、处理进程间通信等。CLONE_PARENT_SETTID 可以帮助父进程或控制者直接获取子进程的 PID,避免了额外的查询操作。

  1. 调用函数 wake_up_new_task 以唤醒新进程。
  2. 如果是系统调用 vfork,那么当前进程等待子进程装载程序。

2. do_fork中copy_process流程

创建fork新进程的主要工作由函数 copy_process 实现

官方注释——只执行复制但是不启动,state设置为TASK_NEW
This creates a new process as a copy of the old one, but does not actually start it yet.
It copies the registers, and all the appropriate parts of the process environment (as per the clone flags). The actual kick-off is left to the caller.
copy_process流程

接下来我们详细解读一下copy_process中每个流程

(1). 标志冲突判断
  • CLONE_NEWNS & CLONE_FS:

    • CLONE_NEWNS 会创建一个新的挂载命名空间,意味着新的进程有一个独立的根目录(根文件系统)。而 CLONE_FS 是要求多个进程共享文件系统信息,包括根目录。如果同时设置这两个标志,会导致根目录和文件系统信息冲突,因此是无效的。
  • CLONE_NEWUSER & CLONE_FS:

    • CLONE_NEWUSER 创建新的用户命名空间,使得新的进程具有独立的用户身份。而 CLONE_FS 会共享文件系统信息,这会导致新进程在文件系统方面不独立,违反了用户命名空间的隔离原则,因此这两个标志不能同时使用。
  • CLONE_THREAD & !CLONE_SIGHAND:

    • 线程组的进程必须共享信号处理程序。因此,当设置 CLONE_THREAD 时,必须设置 CLONE_SIGHAND 来共享信号处理程序。如果没有设置 CLONE_SIGHAND,则无法确保线程组的一致性,导致冲突。
  • CLONE_SIGHAND & !CLONE_VM:

    • 当进程共享信号处理程序(CLONE_SIGHAND)时,必须共享虚拟内存空间(CLONE_VM)。如果不共享虚拟内存,信号处理程序会因进程间内存空间不同而无法正常工作,因此此组合会产生冲突。
  • CLONE_PARENT & SIGNAL_UNKILLABLE:

    • CLONE_PARENT 要求子进程的父进程为当前进程。全局 init 进程(init)是不可杀死的且没有父进程,因此不允许全局 init 进程创建其他兄弟进程。否则,会违反进程树结构,产生冲突。
  • CLONE_THREAD & (CLONE_NEWUSER | CLONE_NEWPID):

    • 线程不允许跨越用户或 PID 命名空间。如果创建一个线程时,设置了 CLONE_NEWUSER 或 CLONE_NEWPID,则该线程将进入一个不同的命名空间,这会破坏线程组的共享,因此是无效的。
  • CLONE_PIDFD & CLONE_DETACHED:

    • 如果设置了 CLONE_PIDFD,表示父进程会持有子进程的 PID 文件描述符,允许父进程跟踪子进程。而 CLONE_DETACHED 表示子进程是分离的,不需要父进程等待,因此不能同时设置这两个标志。分离进程不应持有 PID 文件描述符。
(2). dup_task_struct——分配task空间

函数 dup_task_struct:函数 dup_task_struct 为新进程的进程描述符分配内存,把当前进程的进程描述符复制一份,为新进程分配内核栈。

内核栈——task_struct中的stack指向内核栈
内核栈布局

  1. 分配内核栈和 task_struct 所需空间

    • 每个进程在内核中有一块私有栈(内核栈),和 task_struct 一起分配。
  2. 复制当前进程的 task_struct 数据到新结构体中

    • 这是“浅拷贝”,后续会由 copy_xxx() 函数根据CLONE_FLAG深拷贝处理(比如 copy_mm()、copy_files() 等)。
  3. 初始化调试字段、引用计数

    • 比如清除 task_struct->stack_canary,初始化调试状态。
(3). 检查用户的进程数量限制

对于普通用户:如果创建的进程数量超限,则失败
对于根用户:因为根用户默认拥有忽略资源限制的权限(CAP_SYS_RESOURCE)和系统管理权限(CAP_SYS_ADMIN),可以创建

(4). copy_creds复制或共享证书

什么是 cred 证书?
回答 :
cred(全称 struct cred)是 Linux 内核中用于描述进程安全相关信息的一种核心数据结构。它就是**“进程的身份证 + 安全通行证”,内核通过它判断当前进程能不能干某件事**。


🔐 cred 结构体包含什么?

这个结构体定义在 include/linux/cred.h 中,里面包含了以下这些字段(简化版):

字段含义
uid, gid实际用户/组 ID
euid, egid有效用户/组 ID
suid, sgid保存的用户/组 ID(用于切换身份)
fsuid, fsgid文件系统相关的用户/组 ID(用于访问控制)
cap_inheritable可继承的能力(capabilities)
cap_permitted被允许的能力
cap_effective当前生效的能力(实际起作用的)
cap_bsetbounding set,允许继承的最大能力集合
user指向 struct user_struct,跟踪用户的资源使用(比如进程数)
security安全模块使用(如 SELinux、AppArmor)

🧠 作用是什么?

内核中,几乎所有需要安全判断的操作,比如:

  • 访问文件
  • 打开 socket
  • 调用某些系统调用(比如 mountkillptrace
  • 进入 namespace
  • 修改资源限制
  • 获取 debug 权限(如 /proc/*

都会通过 current->cred 来做决策。

比如:

if (capable(CAP_SYS_ADMIN)) {// 允许系统管理操作
}

这里的 capable() 内部其实就是读取当前线程的 cred->cap_effective,看看有没有这个 capability。


🐾 谁用它?

除了内核自身判断权限外,像:

  • ptrace()
  • setuid(), setgid()
  • capset()
  • LSM(如 SELinux)
  • 容器安全模型

都会操作或依赖 cred

一句话总结
cred是进程的安全身份信息,它决定了一个进程能干什么、能访问什么、有没有权限。


对于kernel_clone(do_fork)copy_cred() 如果设置了标志 CLONE_THREAD,即新进程和当前进程属于同一个线程组,那么新进程和当前进程共享证书。
否则,复制cred。

在这里插入图片描述


(5). 检查线程数量限制

全局变量nr_threads 存放当前的线程数量;max_threads存放允许创建的线程最大数量,默认值是 MAX_THREADS。
如果线程数量达到允许的线程最大数量,那么不允许创建新进程。

(6). sched_fork——设置调度器相关参数
  1. 将task->state设为TASK_NEW,确保新进程不会被运行,也不会被信号唤醒不会被加入就绪队列rq(runqueue)
  2. 把新进程的调度优先级设置为当前进程的正常优先级
    • 因为当前进程可能因为占有实时互斥锁而被临时提升了优先级
  3. unlikely检查是否设置了SCHED_RESET_ON_FORK 标志,要求创建新进程时把新进程的调度策略和优先级设置为默认值
  4. 拒绝dl(dealline)任务fork
  5. SMP 多核支持初始化
(7). copy_xxx——根据CLONE_FLAG复制或共享资源

Linux 内核在创建新进程时执行的一系列子系统状态复制流程,它的作用是将父进程的资源、状态等复制或共享给子进程,以确保新进程具有完整的运行环境。
✅ 步骤及作用一览表
5-10步骤中,只有相同线程组的线程间才会进行共享,人话:一个老爹生的

步骤函数调用作用失败时回滚标签
1perf_event_init_task(p, clone_flags)初始化 perf 事件监控(性能分析支持)bad_fork_sched_cancel_fork
2audit_alloc(p)初始化审计上下文,用于安全审计(audit 子系统)bad_fork_cleanup_perf
3shm_init_task(p)初始化与 System V 共享内存相关的结构无回滚(无失败)
4security_task_alloc(p, clone_flags)安全模块(如 SELinux)相关初始化bad_fork_cleanup_audit
5copy_semundo(clone_flags, p)复制 System V 信号量 undo 状态bad_fork_cleanup_security
6copy_files(clone_flags, p, args->no_files)复制或共享文件描述符表(如 open filesbad_fork_cleanup_semundo
7copy_fs(clone_flags, p)复制或共享文件系统信息(如 cwd、root)bad_fork_cleanup_files
8copy_sighand(clone_flags, p)复制或共享信号处理器(signal handler)bad_fork_cleanup_fs
9copy_signal(clone_flags, p)复制或共享信号状态(阻塞信号集等)bad_fork_cleanup_sighand
10copy_mm(clone_flags, p)复制或共享内存描述符(内存空间)bad_fork_cleanup_signal
11copy_namespaces(clone_flags, p)创建或共享命名空间(如 UTS、IPC、Mount 等)bad_fork_cleanup_mm
12copy_io(clone_flags, p)复制或共享 IO 上下文(如 IO调度器相关)bad_fork_cleanup_namespaces
13copy_thread(p, args)初始化线程状态:栈、寄存器、TLS 等bad_fork_cleanup_io

3. do_fork中的wake_up_new_task流程

那么在结束copy_process流程后,一个新的进程或线程就创建成功了,接下来就是要去运行它,还记得在copy_process()/sched_fork()中将task->state置为TASK_NEW的作用吗?那么在wake_up_new_task中把新进程的状态从 TASK_NEW 切换到 TASK_RUNNING

在 SMP 系统上,创建新进程是执行负载均衡的绝佳时机,为新进程选择一个负载最轻的处理器。


这时使用__set_task_cpu()将任务放到负载最轻的处理器上,实现负载均衡

流程:

  1. 调整state为running
  2. __set_task_cpu(),负载均衡
  3. 锁rq
  4. 更新rq
  5. 释放锁

至此,一个新进程/线程的创建就正式结束了。

3. 进程的退出

3.1 退出概念简介

退出,又分为

  • 主动退出
    • exit,exit_group
  • 被动退出
    • kill,tgkill 被信号通知退出

当进程退出的时候,根据父进程是否关注子进程退出事件,处理存在如下差异。
(1)如果父进程关注子进程退出事件,那么进程退出时释放各种资源,只留下一个空的进程描述符,变成僵尸进程(即task_struct没有被完全释放)[因为系统需要保留一些关于子进程的信息,供父进程查询(例如子进程的退出状态)],发送信号 SIGCHLD(CHLD 是 child 的缩写)通知父进程,父进程在查询进程终止的原因以后回收子进程的进程描述符。
(2)如果父进程不关注子进程退出事件,那么进程退出时释放各种资源,释放进程描述符,自动消失。进程默认关注子进程退出事件,如果不想关注,可以使用系统调用 sigaction 针对信号SIGCHLD 设置标志 SA_NOCLDWAIT(CLD 是 child 的缩写),以指示子进程退出时不要变成僵尸进程,或者设置忽略信号 SIGCHLD。

3.2 exit_group线程组退出

1. exit_group简介

exit_group() 可以被看作是 信号传递式退出函数 的一种典型代表,它的语义是:终止整个线程组(即进程的所有线程)。

🧠 和普通 exit() 的区别:

函数影响范围特点
exit()仅当前线程不会终止进程中其他线程
exit_group()当前线程 + 同一进程中的所有线程会向整个线程组中的所有线程发出终止信号

🧩 内核行为概览

  • exit_group() 最终调用的是 do_group_exit()
  • 它会设置 signal->group_exit_code,标记线程组整体退出;
  • 然后会逐个 wake up 其他线程,让它们也进入退出流程;
  • 所有线程会逐个进入 do_exit(),释放资源、触发钩子等。

📦 为什么说它是“信号式”的?

尽管 exit_group() 本质是一个系统调用,但其实现通过内部机制模拟了类似“信号传播”的退出方式: 通过共享的 struct signal_struct 对线程组成员**“广播”退出状态**,这就像是“向整个线程组传递了一个退出意图”。

2. exit_group具体流程

exit_group流程
假设一个线程组有两个线程,称为线程 1 和线程 2,线程 1 调用 exit_group 使线程组退
出,线程 1 的执行过程如下。
(1)把退出码保存在信号结构体的成员 group_exit_code 中,传递给线程 2。
(2)给线程组设置正在退出的标志。
(3)向线程 2 发送杀死信号,然后唤醒线程 2,让线程 2 处理杀死信号。
(4)线程 1 调用函数 do_exit 以退出。
线程 2 退出的执行流程如下图所示,线程 2 准备返回用户模式的时候,发现收到
了杀死信号,于是处理杀死信号
,调用函数 do_group_exit,函数 do_group_exit 的执行过
程如下。
收到信号退出

3.3 kill

系统调用 kill(源文件“kernel/signal.c”)负责向线程组或者进程组发送信号。
(1)如果参数 pid 大于 0,那么调用函数 kill_pid_info 来向线程 pid 所属的线程组发送信号。
(2)如果参数 pid 等于 0,那么向当前进程组发送信号。
(3)如果参数 pid 小于−1,那么向组长标识符为-pid 的进程组发送信号。
(4)如果参数 pid 等于−1,那么向除了 1 号进程和当前线程组以外的所有线程组发送信号。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/902544.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人像面部关键点检测

此工作为本人近期做人脸情绪识别,CBAM模块前是否能加人脸关键点检测而做的尝试。由于创新点不是在于检测点的标注,而是CBAM的改进,因此,只是借用了现成库Dilb与cv2进行。 首先,下载人脸关键点预测模型:Index of /file…

【Python】每隔一段时间自动清除网站上cookies的方法

我在写爬虫的时候,经常会因为点击浏览太多的页面,而导致很多的cookies累积。 虽然单个Cookie很小,但长期积累可能占用浏览器存储空间,导致浏览器运行变慢(尤其对老旧设备)。 而且Cookies(尤其…

非隔离电源芯片WT5104

非隔离电源芯片WT5104 非隔离电源芯片 WT5104 介绍 WT5104 是一款超高效且高精度的非隔离降压开关电源恒压控制驱动芯片,在各类电源转换场景中提供5V辅助电源供电发挥着重要作用。 一、芯片特点 高集成度:内部集成 800V 功率 MOSFET,极大减…

基于 Python 的自然语言处理系列(83):InstructGPT 原理与实现

📌 论文地址:Training language models to follow instructions with human feedback 💻 参考项目:instructGOOSE 📷 模型架构图: 一、引言:为什么需要 InstructGPT? 传统的语言模型…

零基础入门 Verilog VHDL:在线仿真与 FPGA 实战全流程指南

摘要 本文面向零基础读者,全面详解 Verilog 与 VHDL 两大主流硬件描述语言(HDL)的核心概念、典型用法及开发流程。文章在浅显易懂的语言下,配合多组可在线验证的示例代码、PlantUML 电路结构图,让你在 EDA Playground 上动手体验数字电路设计与仿真,并深入了解从 HDL 编写…

Kubernetes控制平面组件:API Server详解(二)

云原生学习路线导航页(持续更新中) kubernetes学习系列快捷链接 Kubernetes架构原则和对象设计(一)Kubernetes架构原则和对象设计(二)Kubernetes架构原则和对象设计(三)Kubernetes控…

云服务器存储空间不足导致的docker image运行失败或Not enough space in /var/cache/apt/archives

最近遇到了两次空间不足导致docker实例下的mongodb运行失败的问题。 排查错误 首先用nettools看下mongodb端口有没有被占用: sudo apt install net-tools netstat --all --program | grep 27017 原因和解决方案 系统日志文件太大 一般情况下日志文件不会很大…

爬虫学习——下载文件和图片、模拟登录方式进行信息获取

一、下载文件和图片 Scrapy中有两个类用于专门下载文件和图片,FilesPipeline和ImagesPipeline,其本质就是一个专门的下载器,其使用的方式就是将文件或图片的url传给它(eg:item[“file_urls”])。使用之前需要在settings.py文件中对其进行声明…

拒绝用电“盲人摸象”,体验智能微断的无缝升级

🌟 为什么需要智能微型断路器? 传统断路器只能被动保护电路,而安科瑞智能微型断路器不仅能实时监测用电数据,还能远程控制、主动预警,堪称用电安全的“全能卫士”!无论是家庭、工厂还是商业楼宇&#xff0…

如何优雅地为 Axios 配置失败重试与最大尝试次数

在 Vue 3 中,除了使用自定义的 useRequest 钩子函数外,还可以通过 axios 的拦截器 或 axios-retry 插件实现接口请求失败后的重试逻辑。以下是两种具体方案的实现方式: 方案一:使用 axios 拦截器实现重试 实现步骤: 通…

【Leetcode刷题随笔】242.有效的字母异位词

1. 题目描述 给定两个仅包含小写字母的字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的 字母异位词。 字母异位词定义:两个字符串包含的字母种类和数量完全相同,但顺序可以不同(例如 “listen” 和 “silent”)。 …

示例:spring xml+注解混合配置

以下是一个 Spring XML 注解的混合配置示例,结合了 XML 的基础设施配置(如数据源、事务管理器)和注解的便捷性(如依赖注入、事务声明)。所有业务层代码通过注解简化,但核心配置仍通过 XML 管理。 1. 项目结…

Crawl4AI:打破数据孤岛,开启大语言模型的实时智能新时代

当大语言模型遇见数据饥渴症 在人工智能的竞技场上,大语言模型(LLMs)正以惊人的速度进化,但其认知能力的跃升始终面临一个根本性挑战——如何持续获取新鲜、结构化、高相关性的数据。传统数据供给方式如同输血式营养支持&#xff…

【机器学习-周总结】-第4周

以下是本周学习内容的整理总结,从技术学习、实战应用到科研辅助技能三个方面归纳: 文章目录 📘 一、技术学习模块:TCN 基础知识与结构理解🔹 博客1:【时序预测05】– TCN(Temporal Convolutiona…

Mysql--基础知识点--79.1--双主架构如何避免回环复制

1 避免回环过程 在MySQL双主架构中,GTID(全局事务标识符)通过以下流程避免数据回环: 1 事务提交与GTID生成 在Master1节点,事务提交时生成一个全局唯一的GTID(如3E11FA47-71CA-11E1-9E33-C80AA9429562:2…

安宝特科技 | AR眼镜在安保与安防领域的创新应用及前景

随着科技的不断进步,增强现实(AR)技术逐渐在多个领域展现出其独特的优势,尤其是在安保和安防方面。AR眼镜凭借其先进的功能,在机场、车站、海关、港口、工厂、园区、消防局和警察局等行业中为安保人员提供了更为高效、…

Linux第十讲:进程间通信IPC

Linux第十讲:进程间通信IPC 1.进程间通信介绍1.1什么是进程间通信1.2为什么要进程间通信1.3怎么进行进程间通信 2.管道2.1理解管道2.2匿名管道的实现代码2.3管道的五种特性2.3.1匿名管道,只能用来进行具有血缘关系的进程进行通信(通常是父子)2.3.2管道文…

微信小程序通过mqtt控制esp32

目录 1.注册巴法云 2.设备连接mqtt 3.微信小程序 备注 本文esp32用的是MicroPython固件,MQTT服务用的是巴法云。 本文参考巴法云官方教程:https://bemfa.blog.csdn.net/article/details/115282152 1.注册巴法云 注册登陆并新建一个topic&#xff…

SQLMesh隔离系统深度实践指南:动态模式映射与跨环境计算复用

在数据安全与开发效率的双重压力下,SQLMesh通过动态模式映射、跨环境计算复用和元数据隔离机制三大核心技术,完美解决了生产与非生产环境的数据壁垒问题。本文提供从环境配置到生产部署的完整实施框架,助您构建安全、高效、可扩展的数据工程体…

Spring Data详解:简化数据访问层的开发实践

1. 什么是Spring Data? Spring Data 是Spring生态中用于简化数据访问层(DAO)开发的核心模块,其目标是提供统一的编程模型,支持关系型数据库(如MySQL)、NoSQL(如MongoDB)…