当前位置: 首页 > news >正文

Linux 内核线程

文章目录

  • 一、内核线程
  • 二、内核线程与普通进程的异同
  • 三、内核线程创建
    • 3.1 kernel_thread
    • 3.2 kthread_create
  • 四、内核线程的退出
  • 四、示例代码
    • 参考资料

一、内核线程

内核线程就是内核的分身,一个分身可以处理一件特定事情。Linux内核使用内核线程来将内核分成几个功能模块,像kswapd、kflushd等,这在处理异步事件如异步IO时特别有用。内核线程的使用是廉价的,唯一使用的资源就是内核栈和上下文切换时保存寄存器的空间。支持多线程的内核叫做多线程内核(Multi-Threads kernel )。

内核线程的调度由内核负责,一个内核线程处于阻塞状态时不影响其他的内核线程,因为其是调度的基本单位。这与用户线程是不一样的。

内核线程只运行在内核态,不受用户态上下文的拖累。

  • 处理器竞争:可以在全系统范围内竞争处理器资源;
  • 使用资源:唯一使用的资源是内核栈和上下文切换时保持寄存器的空间
  • 调度:调度的开销可能和进程自身差不多昂贵
  • 同步效率:资源的同步和数据共享比整个进程的数据同步和共享要低一些。

二、内核线程与普通进程的异同

  1. 跟普通进程一样,内核线程也有优先级和被调度。 当和用户进程拥有相同的static_prio时,内核线程有机会得到更多的cpu资源。
  2. 内核线程的bug直接影响内核,很容易搞死整个系统, 但是用户进程处在内核的管理下,其bug最严重的情况也只会把自己整崩溃。
  3. 内核线程没有自己的地址空间,所以它们的”current->mm”都是空的。
  4. 内核线程只能在内核空间操作,不能与用户空间交互。

内核线程不需要访问用户空间内存,这是再好不过了。所以内核线程的task_struct的mm域为空.但是刚才说过,内核线程还有核心堆栈,没有mm怎么访问它的核心堆栈呢?这个核心堆栈跟task_struct的thread_info共享8k的空间,所以不用mm描述。

但是内核线程总要访问内核空间的其他内核啊,没有mm域毕竟是不行的。所以内核线程被调用时, 内核会将其task_strcut的active_mm指向前一个被调度出的进程的mm域, 在需要的时候,内核线程可以使用前一个进程的内存描述符。

因为内核线程不访问用户空间,只操作内核空间内存,而所有进程的内核空间都是一样的。这样就省下了一个mm域的内存。

三、内核线程创建

在内核中,有两种方法可以生成内核线程

3.1 kernel_thread

kernel_thread是最基础的创建内核线程的接口, 它通过将一个函数直接传递给内核来创建一个进程, 创建的进程运行在内核空间, 并且与其他进程线程共享内核虚拟地址空间。

init/main.c文件中可以看到使用kernel_thread创建了负责内核初始化的进程。

noinline void __ref rest_init(void)
{struct task_struct *tsk;int pid;rcu_scheduler_starting();/** We need to spawn init first so that it obtains pid 1, however* the init task will end up wanting to create kthreads, which, if* we schedule it before we create kthreadd, will OOPS.*/pid = kernel_thread(kernel_init, NULL, CLONE_FS);...
}

3.2 kthread_create

kthread_create接口,则是标准的内核线程创建接口,也是最常用的方法。

线程创建后,不会马上运行,而是需要将kthread_create() 返回的task_struct指针传给wake_up_process(),然后通过此函数运行线程。

struct task_struct *kthread_create(int (*threadfn)(void *data),void *data,const char namefmt[], ...);
  • threadfn为线程函数;
  • data为线程函数参数;
  • namefmt为线程名称,可被格式化的, 类似printk一样传入某种格式的线程名

此外内核还提供了kthread_run宏定义,它将kthread_create和wake_up_process结合起来,帮助开发者快速创建并启动线程的函数。

// include/linux/kthread.h
#define kthread_run(threadfn, data, namefmt, ...)			   \
({									   \struct task_struct *__k						   \= kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \if (!IS_ERR(__k))						   \wake_up_process(__k);					   \__k;								   \
})

四、内核线程的退出

线程一旦启动起来后,会一直运行,除非该线程主动调用do_exit函数(当线程执行到函数末尾时也会自动调用内核中do_exit()函数),或者其他的进程调用kthread_stop函数,结束线程的运行。

int kthread_stop(struct task_struct *thread);

kthread_stop() 通过发送信号给线程。
如果线程函数正在处理一个非常重要的任务,它不会被中断的。当然如果线程函数永远不返回并且不检查信号,它将永远都不会停止。

在执行kthread_stop的时候,目标线程必须没有退出,否则会Oops。原因很容易理解,当目标线程退出的时候,其对应的task结构也变得无效,kthread_stop引用该无效task结构就会出错。

为了避免这种情况,需要确保线程没有退出,其方法如代码中所示:

thread_func()
{// do your work here// wait to exitwhile(!thread_could_stop()){wait();}
}exit_code()
{kthread_stop(_task);   //发信号给task,通知其可以退出了
}

四、示例代码

#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/delay.h>#define ENTER() printk(KERN_DEBUG "%s() Enter", __func__)
#define EXIT() printk(KERN_DEBUG "%s() Exit", __func__)
#define ERR(fmt, args...) printk(KERN_ERR "%s()-%d: " fmt "\n", __func__, __LINE__, ##args)
#define DBG(fmt, args...) printk(KERN_DEBUG "%s()-%d: " fmt "\n", __func__, __LINE__, ##args)static struct task_struct *test_kthread = NULL;    //定义一个task_struct结构体指针,赋值为NULLstatic int kthread_test_func(void)   //定义一个内核线程要执行的函数
{ENTER();while (!kthread_should_stop()) {DBG("kthread is running");msleep(5000);}EXIT();return 0;
}static __init int kthread_test_init(void)
{ENTER();test_kthread = kthread_run(kthread_test_func, NULL, "kthread-test");  //创建线程kthread-test,并且运行if (!test_kthread) {ERR("kthread_run fail");return -ECHILD;}EXIT();return 0;
}static __exit void kthread_test_exit(void)
{ENTER();if (test_kthread) {DBG("kthread_stop");kthread_stop(test_kthread); //停止内核线程test_kthread = NULL;}EXIT();
}
module_init(kthread_test_init);
module_exit(kthread_test_exit);MODULE_DESCRIPTION("Device_create Driver");
MODULE_LICENSE("GPL");

参考资料

  1. Linux创建内核线程kthread_create的用法介绍
  2. Linux内核线程
  3. linux内核中创建线程方法【转】

相关文章:

Linux 内核线程

文章目录 一、内核线程二、内核线程与普通进程的异同三、内核线程创建3.1 kernel_thread3.2 kthread_create 四、内核线程的退出四、示例代码参考资料 一、内核线程 内核线程就是内核的分身&#xff0c;一个分身可以处理一件特定事情。Linux内核使用内核线程来将内核分成几个功…...

Golang学习之路一七fmt的使用

Golang学习之路一七fmt的使用 格式化参数列表 格式含义%%一个%字面量%b一个二进制整数值(基数为 2)&#xff0c;或者是一个(高级的)用科学计数法表示的指数为 2 的浮点数%c字符型。可以把输入的数字按照 ASCII 码相应转换为对应的字符%d一个十进制数值(基数为 10)%e以科学记数…...

windows使用redis-安装和配置

windows使用redis 安装和配置 下载安装方式一-使用压缩包安装解压到指定的文件Redis安装为Windows服务安装成功 方式二-MSI安装包安装完成 Redis配置远程访问1.修改配置文件redis.windows.conf2.修改完redis配置文件&#xff0c;必须重启redis 下载 先下载Redis for windows 的…...

Kafka系列(一)

内容 该系列主要是复习期间&#xff0c;通过浏览资料记录的一些笔记和重点&#xff0c;用于日常学习和学习后的总结。 组件概念 broker 一个Kafka的集群通常由多个broker组成&#xff0c;这样才能实现负载均衡、以及容错 broker是无状态&#xff08;Sateless&#xff09;的…...

Kotlin中的委托

在Kotlin中&#xff0c;委托是一种强大的设计模式&#xff0c;它允许一个类将其一些职责委托给另一个类。这种机制通过关键字by来实现。委托有助于代码的重用&#xff0c;降低耦合性&#xff0c;并提供更清晰的类设计。在Kotlin中&#xff0c;有两种主要类型的委托&#xff1a;…...

VUE2/3:element ui table表格的显隐列(若依框架)

若依框架自带一个组件&#xff0c;封装了关于表格&#xff0c;展示和隐藏表格列的功能&#xff1b; 使用效果就是这样的&#xff0c;在表格上面&#xff0c;三个框&#xff0c;从左到右分别是隐藏上面搜索&#xff0c;刷新列表&#xff0c;和显隐列的功能&#xff1b; 一、下面…...

PTA-7-4 堆排序

代码如下: #include<iostream> using namespace std; void change(int arr[], int n, int i); int main() {int n,i,end,arr[1000];cin >> n;for (i 0; i < n; i){cin >> arr[i];}//进行一次排序,把最大值放到顶端for (i n/2-1; i > 0; i--){change…...

uniapp滑动页面切换和下拉刷新,触底加载更多(swiper + scroll-view)

因为官方文档乱七八糟的&#xff0c;所以自己来总结下 需求&#xff1a; 常见的上方tag标签切换&#xff0c;下方是页面&#xff0c;上面点击切换&#xff0c;下面页面也切换&#xff0c;下方列表有下拉刷新&#xff0c;触底加载更多 因为这两个组件都是固定高度的&#xff0c;…...

git 删除 submodule 子模块的步骤

实验有效&#xff0c;这里删除了两个 submodule。 1, 执行删除 submodule mkdir tmp1 && cd tmp1 && git clone --recursive ssh://gitaaa.bbb.ccc.git \ && cd ixsolver && git checkout -b abranch_01 \ && git submodule deini…...

一文彻底解析 Compose 的穿透刺客 -- CompositionLocal

Compose 官方说明一直很简洁&#xff1a;CompositionLocal 是通过组合隐式向下传递数据的工具。 两个核心&#xff1a;隐式、向下传递&#xff0c;咋一看很懵&#xff0c;先不着急去理解&#xff0c;我们先看一段非常简单的代码&#xff1a; class MainActivity : ComponentAc…...

iOS 位移枚举NS_OPTIONS(如何实现多个枚举值的同时传入判断)

一、场景 当我们使用枚举这个东西时&#xff0c;有时需要多个枚举值任一一个满足时就ture&#xff0c;但是常用的枚举NS_ENUM定义好的枚举只能挨个判断&#xff0c;写一坨就既不美观也不好阅读&#xff0c;如下&#xff1a; typedef NS_ENUM (NSInteger, RPTestType){RPTestT…...

【Axure高保真原型】树控制内联框架

今天和大家分享树控制内联框架的原型模板&#xff0c;点击树的箭头可以打开或者收起子节点&#xff0c;点击最后一级人物节点&#xff0c;可以切换右侧内联框到对应的页面&#xff0c;左侧的树是通过中继器制作的&#xff0c;使用简单&#xff0c;只需要按要求填写中继器表格即…...

Visual Studio常用快捷键及调试操作

CtrlF10 运行到光标处 调试时候不用一行行按F10了CtrlMM 折叠或展开当前方法CtrlMO 折叠所有方法CtrlML 展开所有方法CtrlEW 自动换行/取消自动换行CtrlU 选中文本转小写CtrlShiftU 选中文本转大写CtrlWinO 启动软键盘F9 光标行加断点CtrlAltB 打开断点窗口 或通过Debug -> …...

MySQL 从零开始:02 MySQL 安装

文章目录 1、下载 MySQL 安装程序2、安装 MySQL 要操作 MySQL &#xff0c;首先要安装 MySQL &#xff0c;本文将一步步展示如何安装 MySQL&#xff0c;简直详细到令人发指。 环境&#xff1a; 操作系统&#xff1a;Windows10 64位MySQL版本&#xff1a;社区版 8.0.11.0 1、下…...

GB28181/GB35114平台LiveGBS何如添加白名单,使指定海康、大华、华为等GB28181摄像头或录像机设备可以免密接入

1、什么是GB/T28181级联 协议定义中的解释如下&#xff1a; 级联 cascadednetworking 两个信令安全路由网关之间按照上下级关系连接,上级中心信令控制服务器通过信令安全路由网 关可调用下级中心信令控制服务器所管辖的监控资源,下级中心信令控制服务器通过信令安全路由网 关向…...

【计算机组成与体系结构Ⅱ】MIPS指令系统(实验)

实验2&#xff1a;MIPS指令系统 一&#xff1a;实验目的 了解和熟悉指令级模拟器。熟练掌握MIPSsim模拟器的操作和使用方法。熟悉MIPS指令系统及其特点&#xff0c;加深对MIPS指令操作语义的理解。熟悉MIPS体系结构。 二&#xff1a;实验要求 采用指令集和流水线操作级模拟器…...

jsonvue-mobile 联动方式说明。

目录 jsonvue-mobile的联动类型分为两种 一种是命令式的&#xff1a; 另一种是响应式的&#xff1a; 联动场景 场景一&#xff1a;某一个字段的值变化时&#xff0c;同步修改另一个字段的值 命令式&#xff1a; 响应式&#xff1a; 场景一演示效果GIF 场景二&#xff…...

abseil中的微操

给分支预测器的建议 原始代码 以下代码用于实现多线程中只调用一次的效果&#xff0c;这里的if大多数情况下都是false&#xff0c;即已经被调用过了。这里是否被调用过用的是一个std::atomic<uint32_t>的原子变量 template <typename Callable, typename... Args>…...

NLP论文阅读记录 - 2022 | WOS 数据驱动的英文文本摘要抽取模型的构建与应用

文章目录 前言0、论文摘要一、Introduction1.1目标问题1.2相关的尝试1.3本文贡献 二.相关工作三.本文方法四 实验效果4.1数据集4.2 对比模型4.3实施细节4.4评估指标4.5 实验结果4.6 细粒度分析 五 总结 前言 Construction and Application of a Data-Driven Abstract Extractio…...

虹科新闻丨LIBERO医药冷链PDF温度计完成2024年航空安全鉴定,可安全空运!

来源&#xff1a;虹科环境监测技术 虹科新闻丨LIBERO医药冷链PDF温度计完成2024年航空安全鉴定&#xff0c;可安全空运&#xff01; 原文链接&#xff1a;https://mp.weixin.qq.com/s/XHT4kU27opeKJneYO0WqrA 欢迎关注虹科&#xff0c;为您提供最新资讯&#xff01; 虹科LIBE…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

Typeerror: cannot read properties of undefined (reading ‘XXX‘)

最近需要在离线机器上运行软件&#xff0c;所以得把软件用docker打包起来&#xff0c;大部分功能都没问题&#xff0c;出了一个奇怪的事情。同样的代码&#xff0c;在本机上用vscode可以运行起来&#xff0c;但是打包之后在docker里出现了问题。使用的是dialog组件&#xff0c;…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

接口自动化测试:HttpRunner基础

相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具&#xff0c;支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议&#xff0c;涵盖接口测试、性能测试、数字体验监测等测试类型…...

上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式

简介 在我的 QT/C 开发工作中&#xff0c;合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式&#xff1a;工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...

鸿蒙(HarmonyOS5)实现跳一跳小游戏

下面我将介绍如何使用鸿蒙的ArkUI框架&#xff0c;实现一个简单的跳一跳小游戏。 1. 项目结构 src/main/ets/ ├── MainAbility │ ├── pages │ │ ├── Index.ets // 主页面 │ │ └── GamePage.ets // 游戏页面 │ └── model │ …...

五子棋测试用例

一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏&#xff0c;有着深厚的文化底蕴。通过将五子棋制作成网页游戏&#xff0c;可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家&#xff0c;都可以通过网页五子棋感受到东方棋类…...