linux有沒(méi)有內(nèi)核級(jí)線(xiàn)程

本文小編為大家詳細(xì)介紹“l(fā)inux有沒(méi)有內(nèi)核級(jí)線(xiàn)程”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“l(fā)inux有沒(méi)有內(nèi)核級(jí)線(xiàn)程”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來(lái)學(xué)習(xí)新知識(shí)吧。

我們提供的服務(wù)有:成都網(wǎng)站制作、成都做網(wǎng)站、外貿(mào)營(yíng)銷(xiāo)網(wǎng)站建設(shè)、微信公眾號(hào)開(kāi)發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、大連ssl等。為1000+企事業(yè)單位解決了網(wǎng)站和推廣的問(wèn)題。提供周到的售前咨詢(xún)和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的大連網(wǎng)站制作公司

linux有內(nèi)核級(jí)線(xiàn)程,linux支持內(nèi)核級(jí)的多線(xiàn)程。Linux內(nèi)核可以看作服務(wù)進(jìn)程(管理軟硬件資源,響應(yīng)用戶(hù)進(jìn)程的各種進(jìn)程);內(nèi)核需要多個(gè)執(zhí)行流并行,為了防止可能的阻塞,支持多線(xiàn)程。內(nèi)核線(xiàn)程就是內(nèi)核的一個(gè)分身,可以用以處理一件特定事情,內(nèi)核線(xiàn)程的調(diào)度由內(nèi)核負(fù)責(zé),一個(gè)內(nèi)核線(xiàn)程的處于阻塞狀態(tài)時(shí)不影響其他的內(nèi)核線(xiàn)程。

線(xiàn)程通常被定義為一個(gè)進(jìn)程中代碼的不同執(zhí)行路線(xiàn)。從實(shí)現(xiàn)方式上劃分,線(xiàn)程有兩種類(lèi)型:“用戶(hù)級(jí)線(xiàn)程”和“內(nèi)核級(jí)線(xiàn)程”。

用戶(hù)線(xiàn)程指不需要內(nèi)核支持而在用戶(hù)程序中實(shí)現(xiàn)的線(xiàn)程,其不依賴(lài)于操作系統(tǒng)核心,應(yīng)用進(jìn)程利用線(xiàn)程庫(kù)提供創(chuàng)建、同步、調(diào)度和管理線(xiàn)程的函數(shù)來(lái)控制用戶(hù)線(xiàn)程。這種線(xiàn)程甚至在象 DOS 這樣的操作系統(tǒng)中也可實(shí)現(xiàn),但線(xiàn)程的調(diào)度需要用戶(hù)程序完成,這有些類(lèi)似 Windows 3.x 的協(xié)作式多任務(wù)。

另外一種則需要內(nèi)核的參與,由內(nèi)核完成線(xiàn)程的調(diào)度。其依賴(lài)于操作系統(tǒng)核心,由內(nèi)核的內(nèi)部需求進(jìn)行創(chuàng)建和撤銷(xiāo),這兩種模型各有其好處和缺點(diǎn)。

用戶(hù)線(xiàn)程不需要額外的內(nèi)核開(kāi)支,并且用戶(hù)態(tài)線(xiàn)程的實(shí)現(xiàn)方式可以被定制或修改以適應(yīng)特殊應(yīng)用的要求,但是當(dāng)一個(gè)線(xiàn)程因 I/O 而處于等待狀態(tài)時(shí),整個(gè)進(jìn)程就會(huì)被調(diào)度程序切換為等待狀態(tài),其他線(xiàn)程得不到運(yùn)行的機(jī)會(huì);而內(nèi)核線(xiàn)程則沒(méi)有各個(gè)限制,有利于發(fā)揮多處理器的并發(fā)優(yōu)勢(shì),但卻占用了更多的系統(tǒng)開(kāi)支。

Windows NT和OS/2支持內(nèi)核線(xiàn)程。Linux 支持內(nèi)核級(jí)的多線(xiàn)程。

linux中的內(nèi)核級(jí)線(xiàn)

1.內(nèi)核線(xiàn)程概述

Linux內(nèi)核可以看作服務(wù)進(jìn)程(管理軟硬件資源,響應(yīng)用戶(hù)進(jìn)程的各種進(jìn)程)

內(nèi)核需要多個(gè)執(zhí)行流并行,為了防止可能的阻塞,支持多線(xiàn)程。

內(nèi)核線(xiàn)程就是內(nèi)核的一個(gè)分身,可以用以處理一件特定事情,內(nèi)核線(xiàn)程的調(diào)度由內(nèi)核負(fù)責(zé),一個(gè)內(nèi)核線(xiàn)程的處于阻塞狀態(tài)時(shí)不影響其他的內(nèi)核線(xiàn)程。

內(nèi)核線(xiàn)程是直接由內(nèi)核本身啟動(dòng)的進(jìn)程。內(nèi)核線(xiàn)程實(shí)際上是將內(nèi)核函數(shù)委托給獨(dú)立的進(jìn)程執(zhí)行,它與內(nèi)核中的其他“進(jìn)程”并行執(zhí)行。內(nèi)核線(xiàn)程經(jīng)常被稱(chēng)之為內(nèi)核守護(hù)進(jìn)程。當(dāng)前的內(nèi)核中,內(nèi)核線(xiàn)程就負(fù)責(zé)下面的工作:

  • 周期性地將修改的內(nèi)存頁(yè)與頁(yè)來(lái)源塊設(shè)備同步

  • 實(shí)現(xiàn)文件系統(tǒng)的事務(wù)日志

內(nèi)核線(xiàn)程由內(nèi)核創(chuàng)建,所以?xún)?nèi)核線(xiàn)程在內(nèi)核態(tài)執(zhí)行,只能訪(fǎng)問(wèn)內(nèi)核虛擬地址空間,不能訪(fǎng)問(wèn)用戶(hù)空間。

在linux所有的線(xiàn)程都當(dāng)作進(jìn)程來(lái)實(shí)現(xiàn),也沒(méi)有單獨(dú)為線(xiàn)程定義調(diào)度算法以及數(shù)據(jù)結(jié)構(gòu),一個(gè)進(jìn)程相當(dāng)于包含一個(gè)線(xiàn)程,就是自身,多線(xiàn)程,原本的線(xiàn)程稱(chēng)為主線(xiàn)程,他們一起構(gòu)成線(xiàn)程組。

進(jìn)程擁有自己的地址空間,所以每個(gè)進(jìn)程都有自己的頁(yè)表,而線(xiàn)程卻沒(méi)有,只能和其它線(xiàn)程共享主線(xiàn)程的地址空間和頁(yè)表

2.三個(gè)數(shù)據(jù)結(jié)構(gòu)

每個(gè)進(jìn)程或線(xiàn)程由三個(gè)重要的數(shù)據(jù)結(jié)構(gòu),分別是struct thread_info, struct task_struct 和內(nèi)核棧。

thread_info對(duì)象存放的進(jìn)程/線(xiàn)程的基本信息,它和進(jìn)程/線(xiàn)程的內(nèi)核棧存放在內(nèi)核空間里的一段2倍頁(yè)長(zhǎng)空間中。其中thread_info結(jié)構(gòu)存放在地址段的末尾,其余空間作為內(nèi)核棧。內(nèi)核使用伙伴系統(tǒng)分配這段空間。

linux有沒(méi)有內(nèi)核級(jí)線(xiàn)程
struct thread_info {

int preempt_count; /* 0 => preemptable, <0 => bug */

struct task_struct *task; /* main task structure */
__u32 cpu; /* cpu */};

thread_info結(jié)構(gòu)體中有一個(gè)struct task_struct *task,task指向該線(xiàn)程或者進(jìn)程的task_struct對(duì)象,task_struct也叫做任務(wù)描述符:

struct task_struct {

pid_t pid;

pid_t tgid;

void *stack;
struct mm_struct *mm, *active_mm;
/* filesystem information */
struct fs_struct *fs;
/* open file information */
struct files_struct *files;};#define task_thread_info(task) ((struct thread_info *)(task)->stack)
  • stack:是指向進(jìn)程或者線(xiàn)程的thread_info

  • mm:對(duì)象用來(lái)管理該進(jìn)程/線(xiàn)程的頁(yè)表以及虛擬內(nèi)存區(qū)

  • active_mm:主要用于內(nèi)核線(xiàn)程訪(fǎng)問(wèn)主內(nèi)核頁(yè)全局目錄

  • pid:每個(gè)task_struct都會(huì)有一個(gè)不同的id,就是pid

  • tgid:線(xiàn)程組領(lǐng)頭線(xiàn)程的PID,就是主線(xiàn)程的pid

linux系統(tǒng)上虛擬地址空間分為兩個(gè)部分:供用戶(hù)態(tài)程序訪(fǎng)問(wèn)的虛擬地址空間和供內(nèi)核訪(fǎng)問(wèn)的內(nèi)核空間。每當(dāng)內(nèi)核執(zhí)行上下文切換時(shí),虛擬地址空間的用戶(hù)層部分都會(huì)切換,以便匹配運(yùn)行的進(jìn)程,內(nèi)核空間的部分是不會(huì)切換的。

3.內(nèi)核線(xiàn)程創(chuàng)建

在內(nèi)核版本linux-3.x以后,內(nèi)核線(xiàn)程的創(chuàng)建被延后執(zhí)行,并且交給名為kthreadd 2號(hào)線(xiàn)程執(zhí)行創(chuàng)建過(guò)程,但是kthreadd本身是怎么創(chuàng)建的呢?過(guò)程如下:

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本身最終是通過(guò)do_fork實(shí)現(xiàn)的,do_fork通過(guò)傳入不同的參數(shù),可以分別用于創(chuàng)建用戶(hù)態(tài)進(jìn)程/線(xiàn)程,內(nèi)核線(xiàn)程等。當(dāng)kthreadadd被創(chuàng)建以后,內(nèi)核線(xiàn)程的創(chuàng)建交給它實(shí)現(xiàn)。

內(nèi)核線(xiàn)程的創(chuàng)建分為創(chuàng)建和啟動(dòng)兩個(gè)部分,kthread_run作為統(tǒng)一的接口,可以同時(shí)實(shí)現(xiàn),這兩個(gè)功能:

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

/*分配kthread_create_info空間*/
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;

/*加入到kthread_creta_list列表中,等待ktherad_add中斷線(xiàn)程去創(chuàng)建改線(xiàn)程*/
spin_lock(&kthread_create_lock);
list_add_tail(&create->list, &kthread_create_list);
spin_unlock(&kthread_create_lock);

wake_up_process(kthreadd_task);
/*
* Wait for completion in killable state, for I might be chosen by
* the OOM killer while kthreadd is trying to allocate memory for
* new kernel thread.
*/
if (unlikely(wait_for_completion_killable(&done))) {
/*
* If I was SIGKILLed before kthreadd (or new kernel thread)
* calls complete(), leave the cleanup of this structure to
* that thread.
*/
if (xchg(&create->done, NULL))
return ERR_PTR(-EINTR);
/*
* kthreadd (or new kernel thread) will call complete()
* shortly.
*/
wait_for_completion(&done);
}
task = create->result;
.
.
.
kfree(create);
return task;
}

kthread_create_on_node函數(shù)中:

  • 首先利用kmalloc分配kthread_create_info變量create,利用函數(shù)參數(shù)初始化create

  • 將create加入kthread_create_list鏈表中,然后喚醒kthreadd內(nèi)核線(xiàn)程創(chuàng)建當(dāng)前線(xiàn)程

  • 喚醒kthreadd后,利用completion等待內(nèi)核線(xiàn)程創(chuàng)建完成,completion完成后,釋放create空間

下面來(lái)看下kthreadd的處理過(guò)程:

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

/* Setup a clean context for our children to inherit. */
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(;;)一直駐留在內(nèi)存中運(yùn)行:主要過(guò)程如下:

  • 檢查kthread_create_list為空時(shí),kthreadd讓出cpu的執(zhí)行權(quán)

  • kthread_create_list不為空時(shí),利用while循環(huán)遍歷kthread_create_list鏈表

  • 每取下一個(gè)鏈表節(jié)點(diǎn)后調(diào)用create_kthread,創(chuàng)建內(nèi)核線(xiàn)程

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


/* We want our own signal handler (we take no signals by default). */
pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
if (pid < 0) {
/* If user was SIGKILLed, I release the structure. */
struct completion *done = xchg(&create->done, NULL);

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

可以看到內(nèi)核線(xiàn)程的創(chuàng)建最終還是和kthreadd一樣,調(diào)用kernel_thread實(shí)現(xiàn)。

static int kthread(void *_create)
{
.
.
.
.
/* If user was SIGKILLed, I release the structure. */
done = xchg(&create->done, NULL);
if (!done) {
kfree(create);
do_exit(-EINTR);
}
/* OK, tell user we're spawned, wait for stop or wakeup */
__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);
}
/* we can't just return, we must preserve "self" on stack */
do_exit(ret);
}

kthread以struct kthread_create_info 類(lèi)型的create為參數(shù),create中帶有創(chuàng)建內(nèi)核線(xiàn)程的回調(diào)函數(shù),以及函數(shù)的參數(shù)。kthread中,完成completion信號(hào)量的處理,然后schedule讓出cpu的執(zhí)行權(quán),等待下次返回 時(shí),執(zhí)行回調(diào)函數(shù)threadfn(data)。

4.內(nèi)核線(xiàn)程的退出

線(xiàn)程一旦啟動(dòng)起來(lái)后,會(huì)一直運(yùn)行,除非該線(xiàn)程主動(dòng)調(diào)用do_exit函數(shù),或者其他的進(jìn)程調(diào)用kthread_stop函數(shù),結(jié)束線(xiàn)程的運(yùn)行。

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

如果線(xiàn)程函數(shù)正在處理一個(gè)非常重要的任務(wù),它不會(huì)被中斷的。當(dāng)然如果線(xiàn)程函數(shù)永遠(yuǎn)不返回并且不檢查信號(hào),它將永遠(yuǎn)都不會(huì)停止。在執(zhí)行kthread_stop的時(shí)候,目標(biāo)線(xiàn)程必須沒(méi)有退出,否則會(huì)Oops。所以在創(chuàng)建thread_func時(shí),可以采用以下形式:

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

exit_code()
{
    kthread_stop(_task);   //發(fā)信號(hào)給task,通知其可以退出了
}

如果線(xiàn)程中在等待某個(gè)條件滿(mǎn)足才能繼續(xù)運(yùn)行,所以只有滿(mǎn)足了條件以后,才能調(diào)用kthread_stop殺掉內(nèi)核線(xiàn)程。

5.內(nèi)核線(xiàn)程使用

#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,
};

讀到這里,這篇“l(fā)inux有沒(méi)有內(nèi)核級(jí)線(xiàn)程”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過(guò)才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

名稱(chēng)欄目:linux有沒(méi)有內(nèi)核級(jí)線(xiàn)程
本文路徑:http://www.muchs.cn/article24/ghpdce.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供營(yíng)銷(xiāo)型網(wǎng)站建設(shè)、網(wǎng)站維護(hù)、網(wǎng)站內(nèi)鏈、關(guān)鍵詞優(yōu)化網(wǎng)站策劃、外貿(mào)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

商城網(wǎng)站建設(shè)