首页 程序笔记 Linux内核编程中通过kthread_create创建内核线程

Linux内核编程中通过kthread_create创建内核线程

前言

在开发Linux的内核驱动或内核模块时,有时候需要创建一个内核线程来做特定的循环动作,比如通过循环拉高拉低gpio设置成方波输出的信号来模拟pwm信号,比如循环控制led的闪灯效果等等。内核线程是工作在内核空间的,不属于任何一个进程,可以发生睡眠,可以通过内核线程创建函数kthread_create来创建内核线程。

相关头文件

内和线程的相关头文件和源码目录如下:

include/linux/kthread.h 
kernel/kthread.c

创建并启动内核线程

kthread_create只是创建内核线程,需要使用wake_up_process函数进行启动,另外,宏函数kthread_run可以执行创建并启动内核线程。

struct task_struct *kthread_create(int (*threadfn)(void *data),
                               void *data,
                               const char namefmt[], ...);
 
/**
 * kthread_run - create and wake a thread.
 * @threadfn: the function to run until signal_pending(current).
 * @data: data ptr for @threadfn.
 * @namefmt: printf-style name for the thread.
 *
 * Description: Convenient wrapper for kthread_create() followed by
 * wake_up_process().  Returns the kthread or ERR_PTR(-ENOMEM).
 */
#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;                                                     \
})

其中kthread_create()只创建了一个内核线程,并没有启动,需要调用函数wake_up_process()来启动线程,所以内核又帮我们定义了一个宏kthread_run来创建和启动内核线程。内核线程创建成功后,会返回一个struct task_struct对象指针,可以在后续使用这个对象指针进行操作。

关闭内核线程

使用到kthread_stop函数:

int kthread_stop(struct task_struct *k);

这个函数是会阻塞等待,直到内核线程退出。该函数内部会调用wait_for_completion()的方法(通过等待队列来实现),阻塞等待内核线程自身的退出。
如果该内核线程已经被设置stop标志了,则会返回1,否则返回0。

完整示例

代码

这里列举一个使用内核线程的简单的demo代码,可作为参考:
demo代码实现的是在模块初始化的时候创建一个内核线程,此内核线程的功能是每隔5秒中打印一条log信息。当我们卸载模块的时候,会关闭该内核线程。

#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结构体指针,赋值为NULL

static int kthread_test_func(void* param)   //内核线程函数
{
        ENTER();
        while (!kthread_should_stop()) {
                DBG(hello 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-demo);  //创建线程kthread-demo,并且运行
        if (!test_kthread) {
                ERR(kthread_run failed!);
                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_AUTHOR(ferris, ferris@coder-feng.com);
MODULE_DESCRIPTION(Device_create Driver);
MODULE_LICENSE(GPL);

编译Makefile

编译内核模块kthread-demo.ko的Makefile如下:

KERNEL_DIR := /lib/modules/$(shell uname -r)/build
obj-m := kthread-demo.o
driver:
        make -C $(KERNEL_DIR) M=pwd modules
clean:
        make -C $(KERNEL_DIR) M=pwd clean

执行make,如果没有报错,生成kthread-demo.ko模块。

安装内核模块

然后执行内核模块安装命令:

sudo insmod kthread-demo.ko

通过dmesg命令查看内核输出日志,如下:

[5185.050096] kthread_test_init() Enter
[5185.051063] kthread_test_init() Exit
[5185.075036] kthread_test_func() Enter
[5185.075039] kthread_test_func()-17: hello kthread is running
[5190.108482] kthread_test_func()-17: hello kthread is running
[5195.225114] kthread_test_func()-17: hello kthread is running
[5200.344320] kthread_test_func()-17: hello kthread is running
[5205.464569] kthread_test_func()-17: hello kthread is running
3

站心网

前言 在开发Linux的内核驱动或内核模块时,有时候需要创建一个内核线程来做特定的循环动作,比如通过循环拉..

为您推荐

如何选择更适合你的 Linux 发行版?

很多人经常会问我这样一个问题:“嘿,你是用Linux的,对吧?我应该使用Linux的哪个版本?我有这个朋友推荐我_____,你觉得怎么样?”我通常会以这样的问题回复:这取决于你想做什么?今天我决定写一篇关于如何选择L..

传统线程技术中创建线程的两种方式

传统的线程技术中有两种创建线程的方式:一是继承Thread类,并重写run()方法;二是实现Runnable接口,覆盖接口中的run()方法,并把Runnable接口的实现扔给Thread。这两种方式大部分人可能都知道,但是为什么这样玩就..

VS创建.NET Core项目使用Docker方式部署到Linux服务器

在 Visual Studio(VS) 中,使用 Docker 方式部署 .NET Core 项目 到 Linux 服务器,可以简化环境管理并提高部署效率。以下是完整教程:1. 在 VS 创建 .NET Core 项目并启用 Docker新建 ASP.NET Core 项目打开 Visu..

.net 通过 HttpClient 下载文件同时报告进度的方法

通过 HttpClient 的 ContentLength 很多时候都可以拿到下载的内容的长度,通过 ReadAsync 可以返回当前读到的长度,将读取到的长度加起来就是已经下载的长度看起来很简单,于是直接给代码private static async Task ..

C#中的线程安全的集合ConcurrentQueue使用示例

在多线程编程中,如何安全地在不同线程之间共享数据是一个非常重要的问题。C# 为我们提供了一些专门设计的线程安全集合,其中之一就是 ConcurrentQueue<T>。它是一种先进先出(FIFO)的数据结构,专门为多线程环境设..

C#13新特性 使用System.Threading.Lock简化线程同步

C# 13 引入了新的线程同步类型 System.Threading.Lock,它通过作用域管理的方式简化了锁的使用,使代码更加清晰可靠。本文将全面介绍 System.Threading.Lock 的功能、适用场景,并提供完整的运行示例程序。1. 什么是..

ASP.NET 使用Entity Framework (EF) 创建迁移修改SQLite数据库表结构

在 ASP.NET 中,使用 Entity Framework (EF) 创建并连接 SQLite 数据库是一种轻量级、高效的数据库管理方式。以下是详细步骤:安装必要的 NuGet 包安装EntityFrameworkCore.Sqlite包:Install-Package Microsoft.Ent..

通过js修改tinymce的编辑器的内容

在网页开发中,TinyMCE是一个流行的富文本编辑器。它允许用户轻松地创建和编辑HTML内容,而无需直接操作代码。然而,有时我们可能需要通过JavaScript来动态修改编辑器中的内容。本文将介绍如何使用JavaScript来修改T..

.NET Core 3.0创建一个单独的可执行文件

一个独立的应用程序是一个很好的方式来共享您的应用程序,因为所有的组件、运行时和框架都包含在应用程序中。您只需提供application.exe文件,而不必担心其他计算机上是否存在框架或运行时安装状态。.NET Core 3.0预..

.NET Core MVC应用程序创建教程

本文主要介绍如何创建一个.NET Core MVC应用程序。和大家一起了解一下.NET Core MVC项目中各个文件的作用。首先准备工作,大家需要安装VS2017 15.7.2版本,安装.NET Core2.0,安装VS的时候选择安装.NET Core相关功能..

ASP.NET MVC View视图 .cshtml文件中创建方法

使用场景是在一个 cshtml 文件中想要递归输出html,所以需要定义一个输出html的方法,它的作用域仅限于这个页面。我们知道可以创建 HTMLHelper扩展方法或者在类中实现一个输出html string的方法。但是我们希望在View..

CentOS7部署发布.NET Core网站Ngnix安装配置图文教程

Linux服务器部署.NET Core网站运行速度更快,最近打算把原来windows server上的网站迁到linux的云服务器上。 顺便记录一下CentOS7安装.NET运行环境,安装和配置Ngnix的过程。首先安装.NET运行时sudorpm-Uvhhttps://p..

Kubernetes(k8s) Linux安装和配置

什么是Kubernetes(k8s)?Kubernetes(通常称为"k8s")是一种用于自动部署、扩展和管理容器化应用程序的开源平台。它提供了一个容器编排和管理系统,可以自动化应用程序的部署、管理和缩放,并确保它们的高可用性。在..

.NET6创建windows服务图文教程

本文记录了使用Visual studio2022创建windows服务,并且安装windows服务设置为自动启动的步骤。1、创建一个worker service新建一个项目,选择辅助角色服务,如图所示:我创建了一个名为WorkerService的项目,创建完..

Linux下RabbitMQ安装和.NET Core使用RabbitMQ.Client操作

RabbitMQ简介AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反..

Linux sed命令关键字匹配文件中整行的任意字符然后替换整行

Linux sed命令关键字匹配文件中整行的任意字符然后替换整行语法:sed -i s/.*要匹配的字串符.*/待替换的字串符/ test.txt例如,文件中内容如下:aabbccddbbccdd要将包含bb的行替换为www,使用如下命令:sed -i s/.*b..

Linux中date命令如何格式化输出需要的时间格式

linux中date命令,可以输出各种格式的时间,有时候在shell脚本中需要获取一定格式的时间字符串,直接使用date命令格式化时间输出就可以完成。date命令的help如下:ferris@ferris-pc:~$ date --help用法:date [选项]..

使用Docker Wine Qemu KVM在Linux运行Windows应用

Docker、Wine、Qemu和KVM都是在Linux上运行Windows程序的工具,但它们的实现方式和使用场景有所不同。Docker是一个容器化技术,它可以在Linux系统中创建和运行容器,这些容器可以包含Windows程序和其所需的依赖项。D..

Debian Linux国内常用镜像源

随着Debian Buster 10.3的发布,Debian Buster 日趋稳定。如果在生产上使用了 Debian 9 的系统,现在是可以安全的,灰度升级到 Debian Buster 做前期验证了。这里我们整理一下国内较知名的镜像站点,供大家在生产环..

Android Studio创建安卓App通过WebView内嵌网页

做了一个react的纯前端的应用,想要使用Android Studio创建一个安卓app通过WebView内嵌。创建app和启动页之前有讲过Android Studio Dolphin创建app启动页Splash自动跳转https://www.leavescn.com/Articles/Content/1..

发表回复

返回顶部