返回顶部
首页 > 资讯 > 操作系统 >linux有没有内核级线程
  • 808
分享到

linux有没有内核级线程

2023-07-04 14:07:14 808人浏览 泡泡鱼
摘要

本文小编为大家详细介绍“linux有没有内核级线程”,内容详细,步骤清晰,细节处理妥当,希望这篇“linux有没有内核级线程”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。linux有内核级线程,linux支持内核

本文小编为大家详细介绍“linux有没有内核级线程”,内容详细,步骤清晰,细节处理妥当,希望这篇“linux有没有内核级线程”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

linux有内核级线程,linux支持内核级的多线程。Linux内核可以看作服务进程(管理软硬件资源,响应用户进程的各种进程);内核需要多个执行流并行,为了防止可能的阻塞,支持多线程。内核线程就是内核的一个分身,可以用以处理一件特定事情,内核线程的调度由内核负责,一个内核线程的处于阻塞状态时不影响其他的内核线程。

线程通常被定义为一个进程中代码的不同执行路线。从实现方式上划分,线程有两种类型:“用户级线程”和“内核级线程”。

用户线程指不需要内核支持而在用户程序中实现的线程,其不依赖于操作系统核心,应用进程利用线程库提供创建、同步、调度和管理线程的函数来控制用户线程。这种线程甚至在象 DOS 这样的操作系统中也可实现,但线程的调度需要用户程序完成,这有些类似 windows 3.x 的协作式多任务。

另外一种则需要内核的参与,由内核完成线程的调度。其依赖于操作系统核心,由内核的内部需求进行创建和撤销,这两种模型各有其好处和缺点。

用户线程不需要额外的内核开支,并且用户态线程的实现方式可以被定制或修改以适应特殊应用的要求,但是当一个线程因 I/O 而处于等待状态时,整个进程就会被调度程序切换为等待状态,其他线程得不到运行的机会;而内核线程则没有各个限制,有利于发挥多处理器的并发优势,但却占用了更多的系统开支。

Windows NT和OS/2支持内核线程。Linux 支持内核级的多线程。

linux中的内核级线

1.内核线程概述

Linux内核可以看作服务进程(管理软硬件资源,响应用户进程的各种进程)

内核需要多个执行流并行,为了防止可能的阻塞,支持多线程。

内核线程就是内核的一个分身,可以用以处理一件特定事情,内核线程的调度由内核负责,一个内核线程的处于阻塞状态时不影响其他的内核线程。

内核线程是直接由内核本身启动的进程。内核线程实际上是将内核函数委托给独立的进程执行,它与内核中的其他“进程”并行执行。内核线程经常被称之为内核守护进程。当前的内核中,内核线程就负责下面的工作:

  • 周期性地将修改的内存页与页来源块设备同步

  • 实现文件系统的事务日志

内核线程由内核创建,所以内核线程在内核态执行,只能访问内核虚拟地址空间,不能访问用户空间。

在linux所有的线程都当作进程来实现,也没有单独为线程定义调度算法以及数据结构,一个进程相当于包含一个线程,就是自身,多线程,原本的线程称为主线程,他们一起构成线程组。

进程拥有自己的地址空间,所以每个进程都有自己的页表,而线程却没有,只能和其它线程共享主线程的地址空间和页表

2.三个数据结构

每个进程或线程由三个重要的数据结构,分别是struct thread_info, struct task_struct 和内核栈。

thread_info对象存放的进程/线程的基本信息,它和进程/线程的内核栈存放在内核空间里的一段2倍页长空间中。其中thread_info结构存放在地址段的末尾,其余空间作为内核栈。内核使用伙伴系统分配这段空间。

linux有没有内核级线程
struct thread_info {

intpreempt_count;

struct task_struct*task;
__u32cpu;};

thread_info结构体中有一个struct task_struct *task,task指向该线程或者进程的task_struct对象,task_struct也叫做任务描述符:

struct task_struct {

pid_t pid;

pid_t tgid;

void *stack;
struct mm_struct *mm, *active_mm;

struct fs_struct *fs;

struct files_struct *files;};#define task_thread_info(task)((struct thread_info *)(task)->stack)
  • stack:是指向进程或者线程的thread_info

  • mm:对象用来管理该进程/线程的页表以及虚拟内存区

  • active_mm:主要用于内核线程访问主内核页全局目录

  • pid:每个task_struct都会有一个不同的id,就是pid

  • tgid:线程组领头线程的PID,就是主线程的pid

linux系统上虚拟地址空间分为两个部分:供用户态程序访问的虚拟地址空间和供内核访问的内核空间。每当内核执行上下文切换时,虚拟地址空间的用户层部分都会切换,以便匹配运行的进程,内核空间的部分是不会切换的。

3.内核线程创建

在内核版本linux-3.x以后,内核线程的创建被延后执行,并且交给名为kthreadd 2号线程执行创建过程,但是kthreadd本身是怎么创建的呢?过程如下:

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);
}

pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);

kthreadadd本身最终是通过do_fork实现的,do_fork通过传入不同的参数,可以分别用于创建用户态进程/线程,内核线程等。当kthreadadd被创建以后,内核线程的创建交给它实现。

内核线程的创建分为创建和启动两个部分,kthread_run作为统一的接口,可以同时实现,这两个功能:

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

#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[],
  ...)
{
DECLARE_COMPLETioN_ONSTACK(done);
struct task_struct *task;


struct kthread_create_info *create = kmalloc(sizeof(*create),
    GFP_KERNEL);

if (!create)
return ERR_PTR(-ENOMEM);
create->threadfn = threadfn;
create->data = data;
create->node = node;
create->done = &done;


spin_lock(&kthread_create_lock);
list_add_tail(&create->list, &kthread_create_list);
spin_unlock(&kthread_create_lock);

wake_up_process(kthreadd_task);

if (unlikely(wait_for_completion_killable(&done))) {

if (xchg(&create->done, NULL))
return ERR_PTR(-EINTR);

wait_for_completion(&done);
}
task = create->result;
.
.
.
kfree(create);
return task;
}

kthread_create_on_node函数中:

  • 首先利用kmalloc分配kthread_create_info变量create,利用函数参数初始化create

  • 将create加入kthread_create_list链表中,然后唤醒kthreadd内核线程创建当前线程

  • 唤醒kthreadd后,利用completion等待内核线程创建完成,completion完成后,释放create空间

下面来看下kthreadd的处理过程:

int kthreadd(void *unused)
{
struct task_struct *tsk = current;


set_task_comm(tsk, "kthreadd");
ignore_signals(tsk);
set_cpus_allowed_ptr(tsk, cpu_all_mask);
set_mems_allowed(node_states[N_MEMORY]);

current->flags |= PF_NOFREEZE;

for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (list_empty(&kthread_create_list))
schedule();
__set_current_state(TASK_RUNNING);

spin_lock(&kthread_create_lock);
while (!list_empty(&kthread_create_list)) {
struct kthread_create_info *create;

create = list_entry(kthread_create_list.next,
   struct kthread_create_info, list);
list_del_init(&create->list);
spin_unlock(&kthread_create_lock);

create_kthread(create);

spin_lock(&kthread_create_lock);
}
spin_unlock(&kthread_create_lock);
}

return 0;
}

kthreadd利用for(;;)一直驻留在内存中运行:主要过程如下:

  • 检查kthread_create_list为空时,kthreadd让出cpu的执行权

  • kthread_create_list不为空时,利用while循环遍历kthread_create_list链表

  • 每取下一个链表节点后调用create_kthread,创建内核线程

static void create_kthread(struct kthread_create_info *create)
{
int pid;



pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
if (pid < 0) {

struct completion *done = xchg(&create->done, NULL);

if (!done) {
kfree(create);
return;
}
create->result = ERR_PTR(pid);
complete(done);
}
}

可以看到内核线程的创建最终还是和kthreadd一样,调用kernel_thread实现。

static int kthread(void *_create)
{
.
.
.
.

done = xchg(&create->done, NULL);
if (!done) {
kfree(create);
do_exit(-EINTR);
}

__set_current_state(TASK_UNINTERRUPTIBLE);
create->result = current;
complete(done);
schedule();

ret = -EINTR;

if (!test_bit(KTHREAD_SHOULD_STOP, &self.flags)) {
__kthread_parkme(&self);
ret = threadfn(data);
}

do_exit(ret);
}

kthread以struct kthread_create_info 类型的create为参数,create中带有创建内核线程的回调函数,以及函数的参数。kthread中,完成completion信号量的处理,然后schedule让出cpu的执行权,等待下次返回 时,执行回调函数threadfn(data)。

4.内核线程的退出

线程一旦启动起来后,会一直运行,除非该线程主动调用do_exit函数,或者其他的进程调用kthread_stop函数,结束线程的运行。

int kthread_stop(struct task_struct *k)
{
struct kthread *kthread;
int ret;

trace_sched_kthread_stop(k);

get_task_struct(k);
kthread = to_live_kthread(k);
if (kthread) {
set_bit(KTHREAD_SHOULD_STOP, &kthread->flags);
__kthread_unpark(k, kthread);
wake_up_process(k);
wait_for_completion(&kthread->exited);
}
ret = k->exit_code;
put_task_struct(k);

trace_sched_kthread_stop_ret(ret);
return ret;
}

如果线程函数正在处理一个非常重要的任务,它不会被中断的。当然如果线程函数永远不返回并且不检查信号,它将永远都不会停止。在执行kthread_stop的时候,目标线程必须没有退出,否则会Oops。所以在创建thread_func时,可以采用以下形式:

thread_func()
{
   // do your work here
   // wait to exit
   while(!thread_could_stop())
   {
          wait();
   }
}

exit_code()
{
    kthread_stop(_task);   //发信号给task,通知其可以退出了
}

如果线程中在等待某个条件满足才能继续运行,所以只有满足了条件以后,才能调用kthread_stop杀掉内核线程。

5.内核线程使用

#include "test_kthread.h"
#include <linux/delay.h>
#include <linux/timer.h>

#include <linux/platfORM_device.h>
#include <linux/fs.h>
#include <linux/module.h>

static struct task_struct *test_thread = NULL;

unsigned int time_conut = 5;

int  test_thread_fun(void *data)
{
int times = 0;
while(!kthread_should_stop())
{
printk("\n   printk %u\r\n", times);
times++;
msleep_interruptible(time_conut*1000);
}

printk("\n   test_thread_fun exit success\r\n\n");

return 0;
}


void reGISter_test_thread(void)
{

test_thread = kthread_run(test_thread_fun , NULL, "test_kthread" );

   if (IS_ERR(test_thread)){
       printk(KERN_INFO "create test_thread failed!\n");
   }  
   else {
       printk(KERN_INFO "create test_thread ok!\n");  
   }

}
static ssize_t kthread_debug_start(struct device *dev, struct device_attribute *attr, char *buf)
{
register_test_thread();

return 0;
}


static ssize_t kthread_debug_stop(struct device *dev, struct device_attribute *attr, char *buf)
{
kthread_stop(test_thread);

return 0;
}


static DEVICE_ATTR(kthread_start,  S_IRUSR,  kthread_debug_start,NULL);
static DEVICE_ATTR(kthread_stop, S_IRUSR,    kthread_debug_stop,NULL);

struct attribute * kthread_group_info_attrs[] =
{
&dev_attr_kthread_start.attr,
&dev_attr_kthread_stop.attr,

NULL,
};

struct attribute_group kthread_group =
{
.name = "kthread",
.attrs = kthread_group_info_attrs,
};

读到这里,这篇“linux有没有内核级线程”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网操作系统频道。

--结束END--

本文标题: linux有没有内核级线程

本文链接: https://lsjlt.com/news/345653.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • linux有没有内核级线程
    本文小编为大家详细介绍“linux有没有内核级线程”,内容详细,步骤清晰,细节处理妥当,希望这篇“linux有没有内核级线程”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。linux有内核级线程,linux支持内核...
    99+
    2023-07-04
  • linux内核有没有中断函数
    这篇文章主要介绍“linux内核有没有中断函数”,在日常操作中,相信很多人在linux内核有没有中断函数问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”linux内核有没有中断函数”的疑惑有所帮助!接下来,请跟...
    99+
    2023-07-04
  • linux有没有内核文件操作函数
    这篇文章主要介绍“linux有没有内核文件操作函数”,在日常操作中,相信很多人在linux有没有内核文件操作函数问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”linux有没有...
    99+
    2023-03-02
    linux
  • linux中进程有没有优先级
    今天小编给大家分享一下linux中进程有没有优先级的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一...
    99+
    2023-04-20
    linux
  • javascript有没有多线程
    这篇文章主要介绍“javascript有没有多线程”,在日常操作中,相信很多人在javascript有没有多线程问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”javascri...
    99+
    2024-04-02
  • 用户级线程与内核级线程——从概念到应用
    一、概念 用户级线程(ULT)也称为轻量级进程。ULT常被称为进程,是指不能被操作系统调度和管理且仅存在于用户空间的线程。ULT也不与硬件及其资源打交道。ULT由用户自己管理,且切换成本低廉,主要用于解决多任务处理的需求,用户在应用程序当...
    99+
    2024-02-03
    用户级线程 内核级线程 并发 线程 模型 操作系统
  • 操作系统:用户级线程与内核级线程之争
    操作系统中的线程可以分为用户级线程和内核级线程,各有利弊。用户级线程的创建和切换开销更小,并且不需要内核的支持,内核级线程的性能更好,但是创建和切换开销更大。 用户级线程 用户级线程是由用户空间的程序创建和管理的,不需要内核的支持。用户...
    99+
    2024-02-06
    操作系统 线程 用户级线程 内核级线程
  • Linux内核 vs Windows内核有什么区别
    这篇文章给大家分享的是有关Linux内核 vs Windows内核有什么区别的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。Windows 和 Linux 可以说是我们比较常见的两款操作系统的。Windows 基本...
    99+
    2023-06-15
  • 用户级线程 VS 内核级线程:操作系统中的线程之争
    在操作系统中,线程是一种轻量级进程,它与进程共享相同地址空间。用户级线程和内核级线程是两种不同的线程实现机制,各有优缺点。 用户级线程 定义:由用户空间的程序或库来管理和调度。 优点: 创建和销毁线程的速度快。 不需要内核参与,因此开销...
    99+
    2024-04-02
  • 对Linux内核进行升级的步骤有哪些
    这篇文章主要讲解了“对Linux内核进行升级的步骤有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“对Linux内核进行升级的步骤有哪些”吧!下载内核代码如下:cd /usr/src<...
    99+
    2023-06-12
  • 操作系统线程剖析:用户级线程与内核级线程的异同
    线程简介 线程是进程中独立执行的基本单元,可以共享进程的数据,并具有独立的程序计数器、堆栈和寄存器等。线程的引入使得程序可以并发执行,从而提高了程序的执行效率。 用户级线程与内核级线程 线程可以分为用户级线程和内核级线程。用户级线程由用...
    99+
    2024-02-06
    线程 用户级线程 内核级线程 进程 并发 调度
  • 用户级线程与内核级线程的调度策略大揭秘
    线程是操作系统中的一种轻量级进程,它与进程共享相同的地址空间,但是拥有自己的独立执行流。线程的出现极大地提高了程序的并发性和可伸缩性。 在操作系统中,线程的调度策略是决定线程如何执行的重要因素。线程的调度策略主要有两种:用户级线程和内核...
    99+
    2024-02-03
    线程;调度策略;用户级线程;内核级线程
  • linux的内核锁有哪些
    linux中的内核锁有:1.互斥锁,在原子操作API的基础上实现的信号量行为;2.自旋锁,为SMP系统设计;linux中的内核锁有以下两种互斥锁linux中互斥锁是在原子操作API的基础上实现的信号量行为,其访问的规则是同一时间只能有一个任...
    99+
    2024-04-02
  • linux内核有哪些作用
    本文小编为大家详细介绍“linux内核有哪些作用”,内容详细,步骤清晰,细节处理妥当,希望这篇“linux内核有哪些作用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。linux内核的作用:1、负责进程的创建和销毁...
    99+
    2023-06-29
  • Java离Linux内核有多远
    这篇文章主要介绍了Java离Linux内核有多远的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java离Linux内核有多远文章都会有所收获,下面我们一起来看看吧。Java 离内核有多远?测试环境版本信息:Ub...
    99+
    2023-06-27
  • Linux内核怎么升级
    这篇文章主要介绍“Linux内核怎么升级”,在日常操作中,相信很多人在Linux内核怎么升级问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Linux内核怎么升级”的疑惑有所帮助!接下来,请跟着小编一起来学习吧...
    99+
    2023-06-28
  • 如何解析混乱的Linux内核实时线程优先级
    本篇文章给大家分享的是有关如何解析混乱的Linux内核实时线程优先级,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。背景Linux会把进程分为普通进程和实时进程,普通进程采用CF...
    99+
    2023-06-16
  • 为Ubuntu升级Linux内核的不同方法有哪些
    这篇文章将为大家详细讲解有关为Ubuntu升级Linux内核的不同方法有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。第一部分:需要重启的内核升级以下方法需要你重启系统以便新的内核生效。以下所有方法都...
    99+
    2023-06-16
  • 用户级线程与内核级线程的性能对比—— 谁主沉浮?
    1. 线程介绍 线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在一个进程中,与同进程的其他线程共享该进程所拥有的全部资源。 一个线程可以创建和销毁多个子线程,每个子线程有自己的运行栈和程序计数器,但线程之间共享同一块...
    99+
    2024-02-03
    用户级线程 内核级线程 性能对比 并发编程
  • 用户级线程与内核级线程的未来发展趋势探究
    用户级线程和内核级线程是两种不同的线程实现方式,它们在原理、优缺点和应用场景上都有所不同。 原理 用户级线程由用户空间的程序库来管理,而内核级线程由操作系统内核来管理。用户级线程的创建、调度和销毁都由用户空间的程序库来完成,而内核级线程...
    99+
    2024-02-03
    用户级线程;内核级线程;并发编程;性能;可移植性;安全性
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作