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
更新于:1个月前相关文章
- linux shell的几种截取字符串的方法
- Linux中date命令如何格式化输出需要的时间格式
- 使用Docker Wine Qemu KVM在Linux运行Windows应用
- Debian Linux国内常用镜像源
- CentOS7安装unzip解压工具命令使用方法
- Linux使用Docker部署.NET6网站图文教程
- Linux中通过命令连接指定WiFi
- 什么是宝塔Linux
- Linux 删除文件或目录 rm 命令
- 怎样在Linux系统 Ubuntu18.04 中安装微信
- C# WebSocket Client在linux连接失败
- Windows多线程编程之使用Windows API CreateThread创建一个线程
- .NET部署到Linux和Windows哪个性能更高?
- CentOS 7 Linux系统中添加新用户并给其授权
- Linux中如何释放DHCP获取的IP地址并重新获取
- Python 中的条件对象——线程同步
- Linux命令大全
- Linux RPM包安装指南
- 解决Linux下无法卸载繁忙文件系统的方法
- Linux磁盘空间管理:释放空间、避免硬盘满、提高性能