如何在queue kthread workd

下次自动登录
现在的位置:
linux内核线程和 kthread_worker
1. 内核线程
内核线程是直接由内核本身启动的进程。内核线程实际上是将内核函数委托为独立的进程,与系统中的其他进程并行执行,完成内核的委托任务,当然只能在内核空间中执行,不能访问用户空间资源。内核线程通常又称为守护进程。他们一般用于执行下列人物:
周期性的将修改的内存页与页来源设备同步,经常用到就是内存文件映射的同步就通过内核线程实现内存数据和磁盘文件数据的同步
2. 在内存页很少的时候,将很少使用的内存页写入交换区
管理延时动作,计划任务等
4. 实现系统的事务日志
下面来看看内核线程的创建过程,内核线程的创建通过数据结构 struct thread_create_info,在kthread.c文件中
struct kthread_create_info
/* Information passed to kthread() from kthreadd. */
int (*threadfn)(void *data);
/* Result passed back to kthread_create() from kthreadd. */
struct task_struct *
struct list_
@threadfn, data:这个参数就是内核线程创建后要执行的函数,也就是内核委托的任务,data成员为函数参数
@node:node表示这个函数要在哪个memory node上面分配内核线程栈
@result:内核线程的进程数据结构
@list: 用于管理要创建的内核线程
内核线程通过函数kthread_create_on_node创建。其实这个函数并没有真正的创建内核线程,只是初始化了一个kthread_create_info结构,并将其加入一个全局列表中。然后唤醒另外一个内核线程来创建真正的内核线程的task_struct。
struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
void *data,
const char namefmt[],
struct kthread_create_
create.threadfn =
create.data =
create.node =
init_completion(&create.done);
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(&create.done);
wake_up_process(kthreadd_task)会唤醒kthreadd_task线程,该线程遍历kthread_create_list这个管理待创建的内核线程的链表。kthreadd_task线程会执行下面的函数:
int kthreadd(void *unused)
struct task_struct *tsk =
/* 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_HIGH_MEMORY]);
current-&flags |= PF_NOFREEZE | PF_FREEZER_NOSIG;
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (list_empty(&kthread_create_list))
//如果kthread_create_list为空,则切换进程
schedule();
__set_current_state(TASK_RUNNING);
spin_lock(&kthread_create_lock);
while (!list_empty(&kthread_create_list)) {
//遍历kthread_create_list
struct kthread_create_info *
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);
static void create_kthread(struct kthread_create_info *create)
#ifdef CONFIG_NUMA
current-&pref_node_fork = create-&
/* 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) {
create-&result = ERR_PTR(pid);
complete(&create-&done);
在create_kthread中,kernel_thread将应用标志调用do_fork创建进程,并把do_fork返回的task_struct赋值给kthread_create_info的result成员。至此内核线程的task_struct表示创建完成。kernel_thread函数将设置寄存器的地址,执行kthread函数,因此,所有的内核线程就可以在调度器下调度运行。
2. kthread_worker
没找到关于这个的资料,也不知道自己的理解对不对了。kthread_worker/kthread_work是一种内核工作的更好的管理方式,可以多个内核线程在同一个worker上工作,共同完成work的工作,有点像线程池的工作方式。下面看看关于这个的数据结构:
typedef void (*kthread_work_func_t)(struct kthread_work *work);
struct kthread_worker {
spinlock_t
struct list_head work_
struct task_struct *
struct kthread_work {
struct list_head
kthread_work_func_t
wait_queue_head_t
先讲讲基本的工作原理,worker表示工作者,也就是线程落,当然这个线程是可以动态附加的,task成员表示当前附加进程。work_list为kthread_work链表,线程从work_list取出work,然后执行 work 的 func 函数,函数的定义如第一行。 有点不明白的是这个函数只有一个kthread_work当作参数,下面会看到这个参数就是包含但钱func的kthread_work本身,只有这么一个参数如果要有和这个work特定参数怎么办。暂时还没理解。
下面看看工作方式, worker和work的初始化就是直接初始化锁,链表和等待队列就可以了:
int kthread_worker_fn(void *worker_ptr)
struct kthread_worker *worker = worker_
struct kthread_work *
WARN_ON(worker-&task);
worker-&task =
set_current_state(TASK_INTERRUPTIBLE); /* mb paired w/ kthread_stop */
if (kthread_should_stop()) {
__set_current_state(TASK_RUNNING);
spin_lock_irq(&worker-&lock);
worker-&task = NULL;
spin_unlock_irq(&worker-&lock);
work = NULL;
spin_lock_irq(&worker-&lock);
if (!list_empty(&worker-&work_list)) {
work = list_first_entry(&worker-&work_list,
struct kthread_work, node);
list_del_init(&work-&node);
spin_unlock_irq(&worker-&lock);
if (work) {
__set_current_state(TASK_RUNNING);
work-&func(work);
smp_wmb(); /* wmb worker-b0 paired with flush-b1 */
work-&done_seq = work-&queue_
smp_mb(); /* mb worker-b1 paired with flush-b0 */
if (atomic_read(&work-&flushing))
wake_up_all(&work-&done);
} else if (!freezing(current))
schedule();
try_to_freeze();
这个函数就是内核线程要执行的主函数,worker-&task = current 把当前内核线程附加到woker上工作。
if (!list_empty(&worker-&work_list)) {
work = list_first_entry(&worker-&work_list,
struct kthread_work, node);
list_del_init(&work-&node);
spin_unlock_irq(&worker-&lock);
这一段从work_list中取出一个work,并在worker上加锁,表示worker正在工作,不能操作
if (work) {
__set_current_state(TASK_RUNNING);
work-&func(work);
smp_wmb(); /* wmb worker-b0 paired with flush-b1 */
work-&done_seq = work-&queue_
smp_mb(); /* mb worker-b1 paired with flush-b0 */
if (atomic_read(&work-&flushing))
wake_up_all(&work-&done);
在当前线程运行work中指定的函数func, work-&flushing表示在当前work上阻塞的线程个数,如果个数不为0,则唤醒所有在work阻塞的进程。
还有一个问题就是为什么那个current一定是内核线程呢,这里有个限制就是 kthread_worker_fn 函数一般作为 kthread_create() 或者 kthread_run()函数的 threadfn 参数运行,因此附加到worker上的线程肯定是内核线程了。还有就是,多个线程可以附加的同一个worker上面,即,将同一个worker结构传给 kthread_run 或者 kthread_create当作 threadfn的参数就可以了。但是一个时间点只有一个内核线程附加到
worker 上面,也就是 worker 的 task 成员。 当在worker上面没有附加线程时,也就是在worker上面工作的线程都不在运行时,这时 worker 只是一个收集内核 work 的容器。看下面的:
bool queue_kthread_work(struct kthread_worker *worker,
struct kthread_work *work)
bool ret =
spin_lock_irqsave(&worker-&lock, flags);
if (list_empty(&work-&node)) {
list_add_tail(&work-&node, &worker-&work_list);
work-&queue_seq++;
if (likely(worker-&task))
wake_up_process(worker-&task);
spin_unlock_irqrestore(&worker-&lock, flags);
这段代码基本没什么问题了。 第一篇博客纪念以下。(*^__^*)
&&&&推荐文章:
【上篇】【下篇】kthread 使用方法
1 使用kthread_create创建线程:
struct task_struct *kthread_create(int (*threadfn)(void *data),void *data,const char *namefmt, ...);
这个函数可以像printk一样传入某种格式的线程名
线程创建后,不会马上运行,而是需要将kthread_create() 返回的task_struct指针传给wake_up_process(),然后通过此函数运行线程。
2. 当然,还有一个创建并启动线程的函数:kthread_run
struct task_struct *kthread_run(int (*threadfn)(void *data),
void *data,
const char *namefmt, ...);
3. 线程一旦启动起来后,会一直运行,除非该线程主动调用do_exit函数,或者其他的进程调用kthread_stop函数,结束线程的运行。&
int kthread_stop(struct task_struct *thread);
kthread_stop() 通过发送信号给线程。
如果线程函数正在处理一个非常重要的任务,它不会被中断的。当然如果线程函数永远不返回并且不检查信号,它将永远都不会停止。
参考:Kernel threads made easy
#include &linux/kthread.h&
static struct task_struct * _
static struct task_struct * _task2;
static struct task_struct * _task3;
static int thread_func(void *data)
wait_queue_head_t timeout_
static int i = 0;
printk(&thread_func %d started/n&, i);
init_waitqueue_head(&timeout_wq);
while(!kthread_should_stop())
interruptible_sleep_on_timeout(&timeout_wq, HZ);
printk(&[%d]sleeping..%d/n&, k, j++);
void my_start_thread(void)
//_task = kthread_create(thread_func, NULL, &thread_func2&);
//wake_up_process(_task);
_task = kthread_run(thread_func, NULL, &thread_func2&);
_task2 = kthread_run(thread_func, NULL, &thread_func2&);
_task3 = kthread_run(thread_func, NULL, &thread_func2&);
if (!IS_ERR(_task))
printk(&kthread_create done/n&);
printk(&kthread_create error/n&);
void my_end_thread(void)
int ret = 0;
ret = kthread_stop(_task);
printk(&end thread. ret = %d/n& , ret);
ret = kthread_stop(_task2);
printk(&end thread. ret = %d/n& , ret);
ret = kthread_stop(_task3);
printk(&end thread. ret = %d/n& , ret);
在执行kthread_stop的时候,目标线程必须没有退出,否则会Oops。原因很容易理解,当目标线程退出的时候,其对应的task结构也变得无效,kthread_stop引用该无效task结构就会出错。
为了避免这种情况,需要确保线程没有退出,其方法如代码中所示:
thread_func()
// do your work here
// wait to exit
while(!thread_could_stop())
exit_code()
kthread_stop(_task);
//发信号给task,通知其可以退出了
这种退出机制很温和,一切尽在thread_func()的掌控之中,线程在退出时可以从容地释放资源,而不是莫名其妙地被人“暗杀”。
文章出处:linux 内核(2)
可以参考另外篇博客:&
以下转自:
最近发现在内核创建线程的时候经常会用到kthread_run()这样的一个调用。于是准备拿出来学习一下。首先看看它的定义之处才发现它是一个宏函数,而不是一个真正意义上的函数。
在include/linux/Kthread.h里有
* 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_should_stop函数或者kthread_stop()函数。那我们具体看看前一个函数到底做了什么吧。
在这个宏里面主要是调用了函数:kthread_create()
这个函数是干什么的呢?在Kernel/Kthread.c里面我们可以看到:
* kthread_create - create a kthread.
* @threadfn: the function to run until signal_pending(current).
* @data: data ptr for @threadfn.
* @namefmt: printf-style name for the thread.
* Description: This helper function creates and names a kernel
* thread. The thread will be stopped: use wake_up_process() to start
* it. See also kthread_run(), kthread_create_on_cpu().
* When woken, the thread will run @threadfn() with @data as its
* argument. @threadfn can either call do_exit() directly if it is a
* standalone thread for which noone will call kthread_stop(), or
* return when 'kthread_should_stop()' is true (which means
* kthread_stop() has been called). The return value should be zero
* or a n it will be passed to kthread_stop().
* Returns a task_struct or ERR_PTR(-ENOMEM).
struct task_struct *kthread_create(int (*threadfn)(void *data),
&&&&&& void *data,
&&&&&& const char namefmt[],
&&&&&& ...)
struct kthread_create_
DECLARE_WORK(work, keventd_create_kthread, &create);
create.threadfn =
create.data =
init_completion(&create.started);
init_completion(&create.done);
* The workqueue needs to start up first:
if (!helper_wq)
&& work.func(work.data);
&& queue_work(helper_wq, &work);
&& wait_for_completion(&create.done);
if (!IS_ERR(create.result)) {
&& va_start(args, namefmt);
&& vsnprintf(create.result-&comm, sizeof(create.result-&comm),
&&&& namefmt, args);
&& va_end(args);
return create.
EXPORT_SYMBOL(kthread_create);
注意到上面的这段英文解释:说这个函数会创建一个名为namefmt的内核线程,这个线程刚创建时不会马上执行,要等到它将kthread_create() 返回的task_struct指针传给wake_up_process(),然后通过此函数运行线程。我们看到creat结构体,我们将传入的参数付给了它,而threadfn这个函数就是创建的运行函数。在使用中我们可以在此函数中调用kthread_should_stop()或者kthread_stop()函数来结束线程。这里我们看到创建线程函数中使用工作队列DECLARE_WORK,我们跟踪一下发现这只是将函数#define
DECLARE_WORK(n, f, d)&&&&& \
struct work_struct n = __WORK_INITIALIZER(n, f, d)
然后再跟进:
#define __WORK_INITIALIZER(n, f, d) {&&&& \
.entry = { &(n).entry, &(n).entry },&&& \
.func = (f),&&&&&& \
.data = (d),&&&&&& \
.timer = TIMER_INITIALIZER(NULL, 0, 0),&&& \
反正目的是创建一个工作组队列,而其中keventd_create_kthread()函数主要是起到创建线程的功能
/* We are keventd: create a thread. */
static void keventd_create_kthread(void *_create)
struct kthread_create_info *create = _
/* 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) {
&& create-&result = ERR_PTR(pid);
&& wait_for_completion(&create-&started);
&& read_lock(&tasklist_lock);
& create-&result = find_task_by_pid(pid);
&& read_unlock(&tasklist_lock);
complete(&create-&done);
再看看kernel_thread()函数最后调用到了哪里:
* Create a kernel thread.
pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
struct pt_
memset(&regs, 0, sizeof(regs));
regs.ARM_r1 = (unsigned long)
regs.ARM_r2 = (unsigned long)
regs.ARM_r3 = (unsigned long)do_
regs.ARM_pc = (unsigned long)kernel_thread_
regs.ARM_cpsr = SVC_MODE;
pid = do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
MARK(kernel_thread_create, &%ld %p&, pid, fn);
EXPORT_SYMBOL(kernel_thread);
好,最后我们看到了线程通过申请进程的pid号来被创建,关键是我们要知道如何使用这个宏函数,也就是如何应用它。要注意的是它调用了创建线程函数,同时也激活了线程。所以代码中调用了它的话就隐含着已经启动一个线程。
注意事项:kthread_stop函数以及函数
(1)&&&&&& 在调用kthread_stop函数时,线程函数不能已经运行结束。否则,kthread_stop函数会一直进行等待。
(2)&&&&&& 线程函数必须能让出CPU,以便能运行其他线程。同时线程函数也必须能重新被调度运行。在例子程序中,这是通过schedule_timeout()函数完成的。
(3)值得一提的是函数,我们需要在开启的线程中嵌入该函数并检查此函数的返回值,否则是不起作用的
可以使用top命令来查看线程(包括内核线程)的CPU利用率。命令如下:
&&&&&& top –p线程号
可以使用下面命令来查找线程号:
&&&&&& ps aux|grep线程名
(4)&线程一旦启动起来后,会一直运行,除非该线程主动调用do_exit函数,或者其他的进程调用kthread_stop函数,结束线程的运行。
&&& int kthread_stop(struct task_struct *thread);
kthread_stop()&通过发送信号给线程。
如果线程函数正在处理一个非常重要的任务,它不会被中断的。当然如果线程函数永远不返回并且不检查信号,它将永远都不会停止。&
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:13338次
排名:千里之外
(1)(1)(1)(1)(1)(1)(1)(1)(1)(2)(1)(2)(1)5635人阅读
应用开发(166)
1 使用kthread_create创建线程:
& & struct task_struct *kthread_create(int (*threadfn)(void *data),
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& & & & & & & & & void *data,
& && &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& & & const char *namefmt, ...);
这个函数可以像printk一样传入某种格式的线程名
线程创建后,不会马上运行,而是需要将kthread_create() 返回的task_struct指针传给wake_up_process(),然后通过此函数运行线程。
2. 当然,还有一个创建并启动线程的函数:kthread_run
& &struct task_struct *kthread_run(int (*threadfn)(void *data),
& && && && && && && && && && && && &void *data,
& & & & & & & & & & & & & & & && &&&const char *namefmt, ...);
3. 线程一旦启动起来后,会一直运行,除非该线程主动调用do_exit函数,或者其他的进程调用kthread_stop函数,结束线程的运行。
& & int kthread_stop(struct task_struct *thread);
kthread_stop() 通过发送信号给线程。
如果线程函数正在处理一个非常重要的任务,它不会被中断的。当然如果线程函数永远不返回并且不检查信号,它将永远都不会停止。
参考:Kernel threads made easy
#include &linux/kthread.h&
static struct task_struct * _
static struct task_struct * _task2;
static struct task_struct * _task3;
static int thread_func(void *data)
wait_queue_head_t timeout_
static int i = 0;
printk(&thread_func %d started/n&, i);
init_waitqueue_head(&timeout_wq);
while(!kthread_should_stop())
interruptible_sleep_on_timeout(&timeout_wq, HZ);
printk(&[%d]sleeping..%d/n&, k, j++);
void my_start_thread(void)
//_task = kthread_create(thread_func, NULL, &thread_func2&);
//wake_up_process(_task);
_task = kthread_run(thread_func, NULL, &thread_func2&);
_task2 = kthread_run(thread_func, NULL, &thread_func2&);
_task3 = kthread_run(thread_func, NULL, &thread_func2&);
if (!IS_ERR(_task))
printk(&kthread_create done/n&);
printk(&kthread_create error/n&);
void my_end_thread(void)
int ret = 0;
ret = kthread_stop(_task);
printk(&end thread. ret = %d/n& , ret);
ret = kthread_stop(_task2);
printk(&end thread. ret = %d/n& , ret);
ret = kthread_stop(_task3);
printk(&end thread. ret = %d/n& , ret);
在执行kthread_stop的时候,目标线程必须没有退出,否则会Oops。原因很容易理解,当目标线程退出的时候,其对应的task结构也变得无效,kthread_stop引用该无效task结构就会出错。
为了避免这种情况,需要确保线程没有退出,其方法如代码中所示:
thread_func()
&&& // do your work here
&&& // wait to exit
&&& while(!thread_could_stop())
&&&&&&&&&& wait();
exit_code()
&&&& kthread_stop(_task);&& //发信号给task,通知其可以退出了
这种退出机制很温和,一切尽在thread_func()的掌控之中,线程在退出时可以从容地释放资源,而不是莫名其妙地被人“暗杀”。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1070574次
积分:14309
积分:14309
排名:第651名
原创:394篇
转载:74篇
评论:347条
(2)(1)(6)(1)(6)(9)(6)(2)(3)(13)(8)(1)(4)(7)(11)(6)(4)(6)(1)(3)(6)(4)(4)(4)(1)(1)(1)(2)(2)(1)(3)(3)(2)(2)(3)(3)(6)(1)(3)(12)(2)(1)(1)(7)(3)(6)(7)(5)(3)(3)(2)(6)(15)(13)(5)(4)(5)(10)(5)(10)(11)(1)(8)(5)(1)(5)(4)(2)(3)(3)(4)(1)(3)(3)(5)(4)(7)(8)(1)(4)(6)(10)(2)(2)(1)(3)(3)(3)(12)(5)(6)(3)(1)(2)(5)(9)(4)(1)(1)(3)(1)(1)(1)(4)(2)(13)(5)(4)(6)(2)本帖子已过去太久远了,不再提供回复功能。}

我要回帖

更多关于 kthread stop 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信