linux进程线程与kernel_clone函数

2023年 7月 19日 79.5k 0

参考文章:

版权声明:本文为CSDN博主「HZero.chen」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:blog.csdn.net/jasonaction…

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:blog.csdn.net/m0_50662680…

fork/vfork/clone/kthread/kernel_clone

kernel_clone 是底层的内核函数,用于实现进程和线程的创建操作。forkvforkclonekthread 都是与之相关的高级函数或系统调用,通过调用 kernel_clone 来创建新的进程或线程,但在具体的参数设置和行为上略有差异

fork 函数原型:

#include 
pid_t fork(void);

vfork 函数原型:

#include 

pid_t vfork(void);

clone 函数原型:

#define _GNU_SOURCE
#include 

int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...);

kthread_create 函数原型:

#include 

struct task_struct *kthread_create(int (*threadfn)(void *data),
                                   void *data,
                                   const char *namefmt,
                                   ...);

kernel_clone 函数原型:

struct kernel_clone_args {
	u64 flags;
	int __user *pidfd;
	int __user *child_tid;
	int __user *parent_tid;
	int exit_signal;
	unsigned long stack;
	unsigned long stack_size;
	unsigned long tls;
	pid_t *set_tid;
	/* Number of elements in *set_tid */
	size_t set_tid_size;
	int cgroup;
	struct cgroup *cgrp;
	struct css_set *cset;
};

pid_t kernel_clone(struct kernel_clone_args* args);

stack : 只在创建线程时有意义, 用来指定线程的用户栈的地址

stack_size:只在创建线程时有意义, 用来指定线程的用户栈的大小

flags : clone 标志

  • CLONE_VM: 共享进程地址空间
  • CLONE_FS: 共享文件系统信息
  • CLONE_FILES: 共享打开文件描述符表
  • CLONE_NOFILES: 子进程不共享打开文件描述符表
  • CLONE_SIGHAND: 共享信号处理程序
  • CLONE_PID: 新进程与父进程拥有相同的进程 ID (PID)
  • CLONE_PIDFD: 共享 pidfd 文件描述符表
  • CLONE_PTRACE: 允许父进程对子进程进行跟踪
  • CLONE_VFORK: 子进程处于 vfork 状态
  • CLONE_VFORKDONE: 等待 vfork 子进程完成
  • CLONE_PARENT: 子进程的父进程被设置为与调用 fork 的进程相同
  • CLONE_THREAD: 创建一个线程而不是独立进程
  • CLONE_SYSVSEM: 共享 System V 信号量
  • CLONE_SETTLS: 设置新进程的 TLS (Thread Local Storage)
  • CLONE_UNTRACED: 对子进程进行跟踪,但不报告其停止状态
  • CLONE_RESTART: 如果父进程在等待期间被信号中断,则重新启动子进程
  • CLONE_PARENT_SETTID: 将子进程设置为父进程中的字段 TID(用于获取新创建线程的线程 ID)
  • CLONE_CHILD_CLEARTID: 在子进程退出时清除子进程中的字段 TID
  • CLONE_CHILD_SETTID: 将子进程设置为子进程中的字段 TID(用于获取线程 ID)
  • CLONE_CHILD_STOPPED: 在创建子进程后将其暂停
  • CLONE_NEWNS: 创建一个新的挂载命名空间
  • CLONE_NEWPIDFD: 创建一个新的 pidfd 命名空间
  • CLONE_NEWUTS: 创建一个新的 UTS 命名空间
  • CLONE_NEWIPC: 创建一个新的 IPC 命名空间
  • CLONE_NEWUSER: 创建一个新的用户命名空间
  • CLONE_NEWPID: 创建一个新的 PID 命名空间
  • CLONE_NEWNET: 创建一个新的网络命名空间
  • CLONE_IO: 新进程共享 I/O 上下文
  • CLONE_NEWCGROUP: 创建一个新的 cgroup 命名空间
  • CLONE_NEWTIME: 创建一个新的时间命名空间

进程和线程

Linux内核中没有定义真正意义上的线程,不论用户态还是内核态的进程/线程,都是由kernel_clone内核函数所创建的可调度的执行流。

内核进程

内核进程(kernel process)是在操作系统内核中运行的特殊进程。与普通用户进程不同,内核进程直接运行在内核态,具有更高的特权级别和访问权限。

内核进程在操作系统的运行中扮演着重要的角色,负责执行和管理内核级任务,包括但不限于以下功能:

  • 系统调度和进程管理:内核进程负责调度和管理所有的进程,分配CPU时间片、处理进程间切换、维护进程的状态等。
  • 设备驱动程序:内核进程包含了设备驱动程序,用于控制和管理系统中的硬件设备,并提供对设备的访问接口。
  • 内存管理:内核进程管理系统的内存资源,包括虚拟内存的分配、页面置换、内存保护等。
  • 内核进程运行在内核空间,拥有直接访问和操作内核数据结构和系统资源的能力。由于其特权级别较高,内核进程对系统的稳定性和安全性非常重要。
    内核进程是由操作系统的内核自身创建的。在操作系统启动时,内核会初始化并创建一些必要的内核进程,这些进程负责执行核心的操作系统功能和服务。

    具体地说,内核进程的创建通常发生在操作系统的启动阶段,它们可以包括但不限于以下几个常见的内核进程:

  • 调度进程(PID=0):调度器是操作系统中负责进程调度的核心组件,它通过特定的内核进程来进行调度算法的执行和进程切换的工作。
  • init进程(PID=1):init进程是操作系统的第一个用户空间进程,它是内核进程中的一个特例。在Linux系统中,init进程是由内核直接创建的,负责启动系统的所有其他进程,并确保系统正常运行。
  • 内核线程管理进程(PID=2):有些内核模块或子系统需要独立的执行环境来处理特定的任务,这些任务由专门的内核进程或内核线程来完成。例如,在Linux系统中,kthreadd进程是一个特殊的内核进程,负责管理和创建其他内核线程。
  • 这些内核进程的创建一般是作为操作系统启动的一部分,由内核自身负责管理和维护。内核进程的数量和具体功能可能因不同的操作系统而有所不同。

    内核线程

    Linux内核线程是在操作系统内核中运行的一种特殊类型的线程。与用户空间的进程不同,内核线程没有独立的地址空间和用户权限,它们运行在内核模式下,并且可以直接访问操作系统的数据结构和核心功能。

    kthreadd(内核线程管理器, PID=2)是Linux内核中的一个特殊进程,它是所有其他内核线程的创建者和管理者。kthreadd是在内核启动时由主线程启动的第一个内核线程。

    kthreadd具有以下功能:

  • 创建新的内核线程:当需要创建一个新的内核线程时,其他部分会将任务提交给kthreadd,并由kthreadd来负责创建相应的线程。
  • 维护内核线程的状态:kthreadd负责维护和管理内核线程的生命周期和状态信息。它会监测线程退出和销毁,并将相关资源释放回系统。
  • 管理线程池:为了提高效率,kthreadd会维护一个线程池,用于重复使用已经退出的线程,而不是总是创建新的线程。
  • 通过kthreadd的存在,可以有效管理内核线程的创建与销毁,并且能够避免频繁地创建和销毁内核线程所带来的性能开销。它在Linux内核中扮演着重要的角色,确保内核线程的有效运行和管理。

    用户进程

    在 Linux 系统中,用户进程是指由用户创建并运行的进程。用户进程是与用户交互、执行应用程序或服务的主要组成部分。

    当用户登录到 Linux 系统时,系统为每个用户分配一个用户空间,用户可以在该空间中创建和运行自己的进程。这些进程通常是通过终端、图形界面或远程连接启动的。

    用户进程可以是各种类型的应用程序,比如文本编辑器、图形界面程序、网络服务器、脚本等。它们执行各种任务,满足用户的需求,实现各种功能。

    在 Linux 中,用户进程的 PID(进程号)通常大于 1,因为 1 号进程是 init 进程或其他类似的系统级进程。用户进程会与其他进程相互作用,共享系统资源,并由操作系统的调度器对其进行管理和调度。

    用户线程

    linux内核中未实现真正意义的线程,而是采用轻量进程作为用户态线程的载体。linux用户线程通常是Posix线程,采用pthread库以及libc中的NTPL(Native POSIX Thread Library),最终调用clone()系统调用函数创建。称之为轻量级进程(LWP, light weight process)。

    clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL
            | CLONE_SETTLS | CLONE_PARENT_SETTID
            | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM
            | 0);
    
    golang GMP 中的 M

    M在linux下就是调用clone()系统调用创建的Posix线程。

    相关文章

    服务器端口转发,带你了解服务器端口转发
    服务器开放端口,服务器开放端口的步骤
    产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
    如何使用 WinGet 下载 Microsoft Store 应用
    百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
    百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

    发布评论