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

linux 内核线程

内核线程类似于用户进程,通常用于并发处理些工作,它是一种在内核空间实现后台任务的方式,并且可以参与时间片轮转调度。

内核线程可以进行繁忙的异步事件处理,也可以睡眠等待某事件的发生,内核线程可以访问内核函数和数据结构。

内核线程可以使用ps命令查看,名称带[]为内核线程。

内核线程的实现流程:

定义一个线程指针

编写线程函数

创建线程

开启线程

停止线程(需接受)

内核线程使用相关函数

#include <linux/kthread.h> //内核线程接口函数头文件

1.定义线程指针
struct task_struct *kernel_thread; 

2.创建内核线程,返回值为创建线程的指针(方法一)
struct task_struct *kthread_create(int (*threadfn)(void *data),
                                    void *data,const char namefmt[], ...);
参数1:线程函数指针,线程开启后将运行此函数
参数2:函数参数data,传递给线程函数
参数3:线程名称,这个函数可以像printk一样传入某种格式的线程名

3.内核线程绑定CPU
/**
 * kthread_bind - bind a just-created kthread to a cpu.
 * @k: thread created by kthread_create().
 * @cpu: cpu (might not be online, must be possible) for @k to run on.
 *
 * Description: This function is equivalent to set_cpus_allowed(),
 * except that @cpu doesn't need to be online, and the thread must be
 * stopped (i.e., just returned from kthread_create()).
 */
void kthread_bind(struct task_struct *k, unsigned int cpu)

4.内核线程创建后不会马上运行,需要通过以下函数启动
int wake_up_process(struct task_struct *p);

创建内核线程函数并运行(方法二)
#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;                                   \
})

5.判断停止线程检测函数 (线程函数内使用)
int kthread_should_stop(void)/*接收到停止信号,返回真.*/

6.停止内核线程函数 (线程函数外使用)
int kthread_stop(struct task_struct *k);
1)该函数发送信号给内核线程,如果线程函数不检测信号也不返回,那么此函数它将一直进行等待
2)在调用kthread_stop函数时,线程函数不能已经运行结束。

7.线程函数的运行
线程函数,内核线程开启后会运行该函数
int threadfunc(void *data);
1)该函数由用户自己实现,函数格式如上所示
2)该函数必须能让出CPU,以便其他线程能够得到执行,也必须能重新得到调度。
 

kernel_thread() kthread_create()/kthread_run()创建内核线程的区别与使用

kernel_thread() 函数创建内核线程

pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
        return do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn,
                (unsigned long)arg, NULL, NULL);
}
代码分析中,kernel_thread()是通过do_fork()进行创建的线程,在2.6的版本中,这种创建内核线程的方式还可以用于驱动模块中,但是在4.x的内核版本中就不可以在驱动模块中使用,也就是说想要使用kernel_thread之内将驱动程序编译进内核才能够创建线程,想要使用insmod方式创建内核线程,就会被拒绝insmod,因为kernel_thread没有EXPORT_SYSMBOL出来。


kthread_create()/kthread_run() 函数创建线程

    将一个函数传递给kernel_thread创建并初始化一个task,该函数接下来负责帮助内核调用daemonize (3.5已经移除了daemonize接口)已转换为内核守护进程,daemonize随后完成一些列操作, 如该函数释放其父进程的所有资源,不然这些资源会一直锁定直到线程结束。阻塞信号的接收, 将kthreadd_task用作守护进程的父进程。
kthread_create需要使用wake_up_process()唤醒,kernel_thread是通过_do_fork来实现的。
两种方式创建线程的方式其实是一种线程,因为,kthrad_run()是一个宏定义,最终调用到kthread_create()
#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()其实也是宏定义
#define kthread_create(threadfn, data, namefmt, arg...) \
        kthread_create_on_node(threadfn, data, -1, namefmt, ##arg)
 
struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
                                           void *data,
                                           int node,
                                           const char namefmt[], ...);
最终是调用到kthread_create_on_node()函数, kthread_create_on_node()已经被EXPORT_SYSMBOL出来,所以,无论是在内核中使用还是在驱动模块中,都可以创建出新线程。
注意:kthreatd_create()创建出的新线程的父进程是kthreadd,在kthread_create创建出的线程也对其上下文环境也进行了清理,所以kthread_create()是比较正统的创建线程的方法。推荐使用kthread_create()的方式创建线程。
 


http://www.kler.cn/news/147815.html

相关文章:

  • dpkg、apt、rpm、yum、dnf使用
  • css优化滚动条样式
  • 【Kotlin】类与接口
  • vue3 终端实现 (vue3+xterm+websocket)
  • ubuntu 安装python3.13
  • React自定义 Hook
  • 人工智能-优化算法和深度学习
  • Android Studio导入项目一直显示正在下载Gradle项目
  • 将图像的rgb数据转成DICOM医学图像格式
  • Git介绍和基础命令解析
  • 玩转微服务-技术篇-JSDOC教程
  • nvm安装以及解决踩坑
  • Java后端使用XWPFDocument生成word文档,踩坑
  • 【心得】XXE漏洞利用个人笔记
  • Python3.6.8升级Python3.12.0版本小记
  • Xshell远程登录AWS EC2 Linux实例
  • Linux—进程状态、僵尸进程、孤独进程、优先级
  • 【攻防世界-misc】reverseMe
  • LFM信号分析
  • 入侵redis之准备---Linux关于定时任务crontab相关知识了解配合理解shell反弹远程控制
  • 淘宝API接口系列:连接商户与消费者的桥梁
  • 【刷题笔记】分糖果||数组||暴力通过||符合思维方式||多案例分析
  • 饰品价格持续下跌,steam搬砖还有搞头吗?
  • 智能优化算法应用:基于蜻蜓算法无线传感器网络(WSN)覆盖优化 - 附代码
  • 锐捷:下一代防火墙修改密码
  • 【Qt】QStackedWidget、QRadioButton、QPushButton及布局实现程序首页自动展示功能
  • Android中根据字符串动态获取资源文件ID
  • 食品行业研发知识管理:企业网盘的选择与优势
  • 人民币已初步具备了国际使用的网络效应/首批疏解的在京部委所属4所高校雄安校区开工建设/墨茉点心局撤出北京市场
  • python读取PDF文件中的指定页码的范围并存储到指定的文件名