内核线程是内核自行创建、仅运行于内核态的轻量级执行流,如kswapd0、kthreadd,mm为NULL、无用户空间上下文、不可被信号中断;主要分周期轮询(如内存回收)和事件唤醒(如日志提交)两类,通过kthread_run()创建,不共享用户地址空间且不参与cgroup资源统计。

内核线程是啥?它真在“后台默默干活”
内核线程不是用户能直接 fork() 或 pthread_create() 出来的那种线程,它是内核自己启动、只运行在内核态的执行流,比如 kthreadd、kswapd0、khungtaskd。它们不走用户空间,不加载 ELF,也不用切换用户页表(mm 字段为 NULL),所以开销极小,且不会被信号中断或被用户态调度策略干扰。
你用 ps -Al | grep '^k.*d$' 看到的那些名字以 k 开头、以 d 结尾的进程,基本都是内核线程——它们不是“守护进程”的用户态模拟,而是内核原生的调度实体。
两类典型用途:周期轮询 vs 事件唤醒
内核线程主要就干这两类活,别看简单,但设计意图非常明确:
-
周期性服务型:比如
kswapd0每隔几十毫秒扫描内存水位,一旦低于pages_low就开始回收页;pdflush(旧内核)或writeback线程定期把脏页刷回块设备。这类线程通常用schedule_timeout()或msleep_interruptible()控制节奏,避免空转耗 CPU。 -
事件驱动型:比如
kthreadd是所有内核线程的“父进程”,它本身不干活,只等其他子线程通过kthread_create_on_node()提交任务后,再调用wake_up_process()唤醒对应线程;又如文件系统日志线程(jbd2/sda1-8)只在事务提交队列非空时才被唤醒。
关键区别在于:前者主动睡、主动醒;后者全程休眠,靠 wait_event_*() 等待显式唤醒。写错唤醒逻辑,线程就永远卡住——没有用户态 SIGKILL 能杀掉它。
和用户线程、轻量级进程(LWP)根本不是一回事
别被“线程”这个词带偏。Linux 内核里压根没有“线程”这个独立调度对象的抽象,只有 task_struct。用户态的 pthread 线程本质是多个共享 mm_struct 的 task_struct(即 LWP),而内核线程的 task_struct->mm == NULL,且它的 active_mm 是借用前一个用户进程的——这是 lazy TLB 切换的关键优化。
这意味着:
时尚购物程序v1.01、全立体设计。此系统由3个Flash动画为主线(正式版带原文件),设计更形象,网站更有吸引力。这种设计在网店系统内绝无仅有,使您的网店与众不同。2、内置音乐播放器,简单灵活的操作即可完成设置,前台任意调用。并带详细说明文件,一看就懂。合理使用此功能,可使网站更富渲染力。3、支持多图显示,每件产品最多可以上传9张图片。4、后台功能强大,销售管理,财务管理,在线支付平台管理等功能
- 内核线程不能访问用户地址空间,
copy_from_user()在它上下文中会直接 panic; - 它无法使用
get_user_pages()或 mmap 相关接口,除非先显式切换 mm(极少见且危险); - 调试时用
/proc/PID/stack看到的调用栈全是内核函数,没有 libc 或用户符号。
怎么创建一个内核线程?别手写 kernel_thread()
老教程常提 kernel_thread() 这个底层接口,但它已标记为 __deprecated,现代驱动和子系统都应改用 kthread_run() 或 kthread_create() + wake_up_process()。
例如:
struct task_struct *tsk = kthread_run(my_worker_fn, data, "mykthread");
如果返回值是 IS_ERR(tsk),说明创建失败(比如内存不足或内核线程数超限),必须检查;成功后线程自动运行,函数退出即线程终止——不需要手动调用 do_exit()。
容易踩的坑:
- 传给线程函数的
data必须是全局或 kmalloc 分配的,不能是栈变量(线程可能在原函数返回后才开始执行); - 线程函数内部若需长时间等待,务必用
wait_event_interruptible()而非 while(1) + schedule(),否则可能被 sysrq+T 杀死时无法响应; - 不要在内核线程里调用可能 sleep 的用户态路径(如
filp_open()),除非你确认当前上下文允许阻塞(比如已用allow_signal()配置过)。
最常被忽略的一点:内核线程没有文件描述符表、不继承信号掩码、也不参与 cgroup 的 cpuacct 统计——它只属于 init_css_set,这点在容器环境排查资源归属时特别容易误判。









