Linux内核多线程实现方法 —— kthread_create函数

kernel_thread()和kthread_run()/kthread_create()的根本区别 1. 函数的作用 首先要说明的是:这几个函数都是用来创建内核线程的。先看一下几个函数关系: 这里有两个长得很像的函数:create_kthread() 和 kthread_create()。(这不是长得像,根本就是一样的好吧,有点难记),这里只是函数封装的很像,但本质上还是kernel_thread() 和 **kthread_create()**这两个函数的区别。 从上面的函数调用便可以看出:... 阅读详情

      Linux内核多线程实现方法 —— kthread_create函数

 

内核经常需要在后台执行一些操作,这种任务就可以通过内核线程(kernle thread)完成独立运行在内核空间的标准进程。内核线程和普通的进程间的区别在于内核线程没有独立的地址空间,mm指针被设置为NULL;它只在内核空间运行,从来不切换到用户空间去;并且和普通进程一样,可以被调度,也可以被抢占。实际上,内核线程只能由其他内核线程创建,在现有的内核线程中创建一个新的内核线程的方法:

kthread_create:创建线程。
struct task_struct *kthread_create(int (*threadfn)(void *data),void *data,const char *namefmt, ...);//注意,第二个参数data用于向线程传递参数

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

kthread_run :创建并启动线程的函数,相当于kthread_create +  wake_up_process功能;

struct task_struct *kthread_run(int (*threadfn)(void *data),void *data,const char *namefmt, ...);
kthread_stop:通过发送信号给线程,使之退出。
int kthread_stop(struct task_struct *thread);线程一旦启动起来后,会一直运行,除非该线程主动调用do_exit函数,或者其他的进程调用kthread_stop函数,结束线程的运行。 但如果线程函数正在处理一个非常重要的任务,它不会被中断的。当然如果线程函数永远不返回并且不检查信号,它将永远都不会停止,因此,线程函数必须能让出CPU,以便能运行其他线程。同时线程函数也必须能重新被调度运行。在例子程序中,这是通过schedule_timeout()函数完成的(下面的例子会看到)。

 

1.      头文件

#include <linux/sched.h>  //wake_up_process()

#include <linux/kthread.h>//kthread_create()、kthread_run()

#include<err.h>             //IS_ERR()、PTR_ERR()

2.      实现

2.1创建线程

在模块初始化时,可以进行线程的创建。使用下面的函数和宏定义:

struct task_struct *kthread_create(int (*threadfn)(void *data),

                           void *data,

                           const char namefmt[], ...);

#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;                                                    \

})

例如:

static struct task_struct *test_task;

static inttest_init_module(void)    //驱动加载函数

{

    int err;

    test_task = kthread_create(threadfunc, NULL, "test_task");

    if(IS_ERR(test_task)){

     printk("Unable to start kernel thread.\n");

      err = PTR_ERR(test_task);

      test_task =NULL;

      return err;

    }

wake_up_process(test_task);
       return 0;
   }

   module_init(test_init_module);

2.2线程函数

在线程函数里,完成所需的业务逻辑工作。主要框架如下所示:

int threadfunc(void *data){

       …

       while(1){

              set_current_state(TASK_UNINTERRUPTIBLE);//将当前的状态表示设置为休眠

if(kthread_should_stop()) break;  //解释见“注意”

              if(){//条件为真

                     //进行业务处理

              }

              else{//条件为假

                     //让出CPU运行其他线程,并在指定的时间内重新被调度

                    schedule_timeout(HZ);   // 休眠,与set_current_state配合使用,需要计算,这里表示休眠一秒

              }

       }

       …

       return 0;

}

注意:

a. 值得一提的是kthread_should_stop函数,我们需要在开启的线程中嵌入该函数并检查此函数的返回值,否则kthread_stop是不起作用的

b. 休眠有两种相关的状态:TASK_INTERRUPTIBLE and TASK_UNINTERRUPTIBLE。它们的惟一却不是处于TASK_UNINTERRUPTIBLE状态的进程会忽略信号,而处于TASK_INTERRUPTIBLE状态的进程如果收到信号会被唤醒并处理信号(然后再次进入等待睡眠状态)。两种状态的进程位于同一个等待队列上,等待某些事件,不能够运行。

c.schedule_time(s*HZ)的参数为节拍数,HZ宏每个系统定义不一样,表示每一秒时钟中断数,如在2.6中为1000,2.4中为100, s为秒单位,例如如果要休眠20ms,则schedule_time(0.02*HZ)就可以了。

2.3结束线程

在模块卸载时,可以结束线程的运行。使用下面的函数:

int kthread_stop(structtask_struct *k);

例如:

static void test_cleanup_module(void)

{

           if(test_task){

               kthread_stop(test_task);

               test_task = NULL;

           }

}

module_exit(test_cleanup_module);

3.       注意事项

(1)       在调用kthread_stop函数时,线程函数不能已经运行结束。否则,kthread_stop函数会一直进行等待。在执行kthread_stop的时候,目标线程必须没有退出,否则会Oops。原因很容易理解,当目标线程退出的时候,其对应的task结构也变得无效,kthread_stop引用该无效task结构就会出错。

(2)       线程函数必须能让出CPU,以便能运行其他线程。同时线程函数也必须能重新被调度运行。在例子程序中,这是通过schedule_timeout()函数完成的。

4.性能测试

可以使用top命令来查看线程(包括内核线程)的CPU利用率。命令如下:

       top–p 线程号

可以使用下面命令来查找线程号:

       psaux|grep 线程名


可以用下面的命令显示所有内核线程:
      ps afx

 

kthread_run创建内核线程的原理 kthread_run是一个宏,用来创建一个进程,并且将其唤醒,其定义在头文件include/linux/kthread.h中. #define kthread_run(threadfn, data, namefmt, ...)               \ ({                                       \     struct task_struc 阅读详情

相关推荐

Linux-BSP-WIFI驱动移植与调试实战——以RTL8189FS为例

本文以RTL8189FS为例,详细介绍了Linux BSP中WiFi驱动移植与调试的全流程。涵盖硬件原理图分析、内核配置、设备树适配、驱动编译加载及问题排查等关键步骤,提供实用的调试技巧和解决方案,帮助开发者高效完成嵌入式WiFi驱动开发。

moon9的博客 398

Linux创建内核线程kthread_create的用法介绍

内核线程是工作在内核空间的,不属于任何一个进程,可以发生睡眠。可以用内核线程来进行一些循环的动作,比如通过循环拉高拉低gpio设置成方波输出的信号,比如循环控制led的闪灯效果等等都可以使用到内核线程kthread_create接口函数。 内核线程的相关代码目录: include/linux/kthread.h kernel/kthread.c 1、创建并启动一个内核线程 struct task_struct *kthread_create(int (*threadfn)(void *data),

Android/Linux驱动开发传帮带学习,让驱动入门门槛更低! 1万+

别再为多相机标定头疼了!用VisionMaster统一坐标系的保姆级教程

本文详细介绍了使用VisionMaster平台解决多相机视觉系统中坐标系统一问题的完整流程。从标定板选择到N点标定,再到实战演练,提供了从原理到落地的全方位指导,帮助工程师高效解决多相机定位引导中的坐标偏差问题。

weixin_38168322的博客 632

内核线程创建-kthread_create

文章参考大概意思就是早期创建内核线程,是交由内核处理,由内核自己完成(感觉好像也不太对呢),创建一个内核线程比较麻烦,会导致内核阻塞。因此就诞生了工作队列以及现在的kthreadd 2号进程。这样我们在创建内核线程时,只需要将消息告诉它们,实际进行内核线程创建的任务有kthreadd完成,感觉类似一个下半部。我环境使用的是kthreadd进行内核线程的创建。

qq_42693685的博客 2493

一文搞懂【Linux 搭建 Dread Hunger 服务器】附本体及Docker部署集群方案

看直播发现了五花八门的开服器和版本,一时兴起按官方文档进行了搭建尝试,所以我的版本基于官方Stream2024.01.10更新的版本,也就是停服时的玩法,应该可以根据mod和补丁魔改成更那些开服器一样的版本,本文不做谈论,注重服务器搭建,毕竟8个人不可能在一个局域网里乱象:首先,我看了大量教程视频,一类是开服器的推广,另一类自建的基本采用Windows搭建,我觉得最离谱的是大部分教程都会教你买一台远程Windows虚拟机???

LHmine的博客 3987

STM32实战开发(71):STM32人脸识别开发教程:基于摄像头模块的人脸识别系统

在嵌入式系统中,STM32凭借其强大的计算性能、丰富的外设接口以及低功耗特性,成为了实现人脸识别系统的理想平台。STM32虽然没有强大的计算能力,但可以通过合理利用外部硬件加速模块,如DSP、GPU、FPGA等,结合轻量级的人脸识别算法,实现高效的人脸识别系统。尽管STM32的计算资源相对有限,但通过合理的优化和使用高效的算法,我们依然能够实现高效的人脸识别功能。在本项目中,我们使用。在STM32开发中,虽然处理能力有限,但通过优化算法和合理利用硬件加速,我们仍然可以实现一个轻量级的、实时的人脸识别系统。

2201_76125393的博客 1662

创建线程kthread_create

kthread_create():创建线程。 struct task_struct *kthread_create(int (*threadfn)(void *data),void *data,const char *namefmt, ...);//注意,第二个参数data用于向线程传递参数 #define kthread_run(threadfn, data, namefmt, ...) \ ({

qq_35399548的博客 1556

【KingSCADA】如何建立硬件系统及相关变量

本篇主要讲解如何定义设备,如何定义变量。KingSCADA3.8的采集系统是指负责和现场设备进行通讯,并采集现场数据和控制现场数据的模块,称之为采集器,也叫IOServer应用,它是一组独立的应用程序,可以脱离KingSCADA3.8软件,它依赖于KingSCADA3.8驱动产品,通过驱动与IO设备进行通讯。采集系统由通讯链路,设备,数据块组成。链路:链路是指计算机通过什么方式(接口)与设备进行连接,链路类别:串口,以太网,GPRS,Modem,通信卡,采集卡,无链路。

做有价值的事,积累有价值的笔记! 1万+

linux内核多线程,Linux内核多线程实现方法 —— kthread_create函数【转】

Linux内核多线程实现方法 —— kthread_create函数内核经常需要在后台执行一些操作,这种任务就可以通过内核线程(kernle thread)完成独立运行在内核空间的标准进程。内核线程和普通的进程间的区别在于内核线程没有独立的地址空间,mm指针被设置为NULL;它只在内核空间运行,从来不切换到用户空间去;并且和普通进程一样,可以被调度,也可以被抢占。实际上,内核线程只能由其他内核线程...

weixin_35555531的博客 524

history 历史命令记录功能如何防坏人(高级)

在 Linux 下面可以使用 history 命令查看用户的所有历史操作,同时 shell 命令操作记录默认保存在用户目录的 .bash_history 文件中。通过这个文件可以查询 shell 命令的执行历史,有助于运维人员进行系统审计和问题排查,同时在服务器遭受黑客攻击后,也可以查询黑客登录服务器的历史命令操作。但是黑客在入侵后,为了抹除痕迹,会删除 .bash_history 文件,这个就需...

墨痕诉清风的博客 1657

【面试系列】数据分析师高频面试题及详细解答

本文为数据分析师岗位提供了详尽的面试题库和解答,涵盖初级、中级和高级三个层次。初级面试题涉及基本的数据处理和统计分析知识,如SQL查询、数据清理和基础统计概念。中级面试题则重点考察数据可视化、复杂查询和数据建模等技能。高级面试题则深入探讨高级统计方法、大数据处理和高级分析工具的使用。通过这些问题和解答,候选人可以全面了解数据分析师岗位所需的技能,帮助其更好地准备面试。常考知识点总结部分则系统归纳了数据分析师岗位的关键技能领域。

在路上的专栏 5228

linux子线程运行的函数_Linux内核多线程实现方法 —— kthread_create函数【转】

Linux内核多线程实现方法 —— kthread_create函数内核经常需要在后台执行一些操作,这种任务就可以通过内核线程(kernle thread)完成独立运行在内核空间的标准进程。内核线程和普通的进程间的区别在于内核线程没有独立的地址空间,mm指针被设置为NULL;它只在内核空间运行,从来不切换到用户空间去;并且和普通进程一样,可以被调度,也可以被抢占。实际上,内核线程只能由其他内核线程...

weixin_32753181的博客 711

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Linux内核多线程实现方法 —— kthread_create函数【转】

转自:http://blog.youkuaiyun.com/sharecode/article/details/40076951 Linux内核多线程实现方法 —— kthread_create函数 内核经常需要在后台执行一些操作,这种任务就可以通过内核线程(kernle thread)完成独立运行在内核空间的标准进程。内核线程和普通的进程间的区别在于内核线程没有独立的地址空间,mm指针被设置为N...

weixin_34260991的博客 124

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Linux内核线程kthread

内核线程和普通的进程间的区别在于内核线程没有独立的地址空间,它只在 内核空间运行,从来不切换到用户空间去;并且和普通进程一样,可以被调度,也可以被抢占。让模块在加载后能一直运行下去的方法——内核线程。要创建一个内核线程有许多种方法,我们这里要学的是最简单的一种。打开include/linux/kthread.h,你就看到了它全部的API,一共三个函数。 struct task_struct kt

情义唯真,友谊方长存 1万+

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Linux内核线程kthread简介【最好的一篇!】

Linux内核可以看作一个服务进程(管理软硬件资源,响应用户进程的种种合理以及不合理的请求)。内核需要多个执行流并行,为了防止可能的阻塞,支持多线程是必要的。内核线程就是内核的分身,一个分身可以处理一件特定事情。内核线程的调度由内核负责,一个内核线程处于阻塞状态时不影响其他的内核线程,因为其是调度的基本单位。这与用户线程是不一样的。因为内核线程只运行在内核态,因此,它只能使用大于PAGE_OFFSET(3G)的地址空间。内核线程和普通的进程间的区别在于内核线程没有独立的地址空间,mm指针被设置为NULL;

m0_74282605的博客 1719

Linux内核多线程

在linux系统中, 我们接触最多的莫过于用户空间的任务,像用户线程或用户进程,因为他们太活跃了,也太耀眼了以至于我们感受不到内核线程的存在,但是内核线程却在背后默默地付出着,如内存回收,脏页回写,处理大量的软中断等,如果没有内核线程那么linux世界是那么的可怕!本文力求与完整介绍完内核线程的整个生命周期,如内核线程的创建、调度等等,当然本文还是主要从内存管理和进程调度两个维度来解析,且不会涉及到具体的内核线程如kswapd的实现,最后我们会以一个简单的内核模块来说明如何在驱动代码中来创建使用内核线程。

qq_28576837的博客 1075

Linux内核多线程实现方法

参考:http://blog.youkuaiyun.com/sharecode/article/details/40076951 1.创建线程方法1kthread_create(): 创建线程;该函数创建线程后,线程不会马上运行 wake_up_process():激活线程运行 struct task_struct *kthread_create(int (*threadfn)(void *data),v...

yellowblue2的专栏 794

Linux 内核线程

先说kernel_thread接口,使用该接口创建的线程,必须在该线程中调用daemonize()函数,这是因为只有当线程的父进程指向”Kthreadd”时,该线程才算是内核线程,而恰好daemonize()函数主要工作便是将该线程的父进程改成“kthreadd”内核线程;但是内核线程总要访问内核空间的其他内核啊,没有mm域毕竟是不行的。所以内核线程被调用时, 内核会将其task_strcut的active_mm指向前一个被调度出的进程的mm域, 在需要的时候,内核线程可以使用前一个进程的内存描述符。

chi's blog 1667

一文搞懂Linux内核之内核线程

Linux内核可以看作服务进程(管理软硬件资源,响应用户进程的各种进程)。内核需要多个执行流并行,为了防止可能的阻塞,支持多线程。内核线程就是内核的一个分身,可以用以处理一件特定事情,内核线程的调度由内核负责,一个内核线程的处于阻塞状态时不影响其他的内核线程。内核线程是直接由内核本身启动的进程。内核线程实际上是将内核函数委托给独立的进程执行,它与内核中的其他“进程”并行执行。内核线程经常被称之为内核守护进程。周期性地将修改的内存页与页来源块设备同步如果内存页很少使用,则写入交换区。

m0_74282605的博客 3090

linux内核编程-----内核线程kthread

一、序言       在linux驱动中需要创建多线程,实现同一时刻执行多个任务。这个时候我们就需要内核机制----kthread。 二、内核API 1.创建线程: struct task_struct *ret = kthread_create(threadfn, data, namefmt, arg...); 2.唤醒线程:       将创建好的线程句柄传入该函数即可运行线程。 i

Pintitus的博客 1040

Linux内核 -- 多线程之kthread的使用

线程函数是内核线程运行时执行的函数。它通常是一个无限循环,直到某种条件使其退出。while (!ssleep(5);return 0;

sz66cm 学习随笔 708
上一篇: DMA基本概念及linux2440下DMA驱动程序编写与测试
下一篇: 牛顿的广义二项式定理---微积分推倒的开始
shareCode
博客等级 码龄15年 125粉丝 40原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值