在内核中处理线程的正确方法? [英] Proper way of handling threads in kernel?

查看:22
本文介绍了在内核中处理线程的正确方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经看到了一些零散的信息,但我似乎无法得出一个最终答案.如何清理内核中的僵尸线程?

I've seen bits of scattered information all around, but I can't seem to get to one final answer. How do you clean up a zombie thread in kernel?

为了确保并产生处理内核中线程的最终正确方法,我想更广泛地提出这个问题.如何在 Linux 内核中创建、终止和清理线程?

Just to make sure, and produce a final correct way of handling threads in kernel, I would like to ask this question more broadly. How do you create, terminate and clean up a thread in the Linux kernel?

到目前为止我所拥有的是:

What I have so far is this:

thread_func:
    exited = 0;
    while (!must_exit)
        do stuff
    exited = 1;
    do_exit(0)

init_module:
    must_exit = 0;
    exited = 1;
    kthread_run(thread_func, ...)    /* creates and runs the thread */

cleanup_module:
    must_exit = 1;
    while (!exited)
        set_current_state(TASK_INTERRUPTIBLE);
        msleep(1);
    /* How do I cleanup? */

我发现最接近清理解决方案的是 release_task,但我没有找到任何谈论它的地方.我想既然线程函数是 kthread_createkthread_run 等,应该有一个 kthread_joinkthread_wait,但是有不是.do_wait 似乎也有可能,但它不需要 struct task_struct *.

The closest thing I have found to the cleanup solution is release_task, but I didn't find anywhere talking about it. I imagined since the thread functions are kthread_create, kthread_run etc, there should be a kthread_join or kthread_wait, but there wasn't. do_wait also seemed likely, but it doesn't take a struct task_struct *.

此外,我不确定 do_exit 是否是一个好主意,或者是否有必要.有人能提出一个关于如何创建、终止和清理 kthread 的最小草图吗?

Furthermore, I am not sure if do_exit is a good idea, or if at all necessary either. Can someone please come up with the minimum sketch of how a kthread should be created, terminated and cleaned up?

推荐答案

做到这一点的正确"方法之一是让您的线程函数检查它是否kthread_should_stop,如果它就返回确实需要停下来.

One of the "right" ways to do this is to have your thread function check if it kthread_should_stop, and simply return if it does need to stop.

您不需要调用do_exit,如果您打算从模块退出函数kthread_stop它,您可能不应该.

You don't need to call do_exit, and if you intend to kthread_stop it from the module exit function, you probably shouldn't.

您可以通过查看 kernel/kthread.c(摘自 Linux 内核 3.3.1):

You can see this by looking at the documentation for kthread_create_on_node in kernel/kthread.c (extract from Linux kernel 3.3.1):

/**
* kthread_create_on_node - 创建一个 kthread.
* @threadfn:运行直到signal_pending(current)的函数.
* @data:@threadfn 的数据指针.
* @node:内存节点号.
* @namefmt:线程的 printf 样式名称.
*
* 说明:此辅助函数创建并命名内核
* 线.线程将被停止:使用wake_up_process()启动
* 它.另见 kthread_run().
*
* 如果线程将被绑定在一个特定的 cpu 上,给出它的节点
* 在@node 中,获取 kthread 堆栈的 NUMA 亲和性,否则给出 -1.
* 被唤醒时,线程将运行@threadfn(),@data 作为它的
* 争论.@threadfn() 要么直接调用 do_exit()
* 没有人会调用kthread_stop()的独立线程,或者
* 当'kthread_should_stop()'为真时返回(这意味着
* kthread_stop() 已被调用).返回值应为零
* 或负错误号;它将被传递给 kthread_stop().
*
* 返回一个 task_struct 或 ERR_PTR(-ENOMEM).
*/

/**
* kthread_create_on_node - create a kthread.
* @threadfn: the function to run until signal_pending(current).
* @data: data ptr for @threadfn.
* @node: memory node number.
* @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().
*
* If thread is going to be bound on a particular cpu, give its node
* in @node, to get NUMA affinity for kthread stack, or else give -1.
* 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 no one 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 negative error number; it will be passed to kthread_stop().
*
* Returns a task_struct or ERR_PTR(-ENOMEM).
*/

kthread_stop 存在匹配"注释:

如果 threadfn() 可以调用 do_exit() 本身,调用者必须确保 task_struct 不会消失.

If threadfn() may call do_exit() itself, the caller must ensure task_struct can't go away.

(我不确定你是怎么做到的——可能是用 get_task_struct 来保持 struct_task.)

(And I'm not sure how you do that - probably holding on to the struct_task with a get_task_struct.)

如果你走线程创建的路径,你会得到类似的东西:

If you walk the path of a thread creation you'll get something like:

kthread_create                                           // macro in kthread.h
  -> kthread_create_on_node                              // in kthead.c
    -> adds your thread request to kthread_create_list
    -> wakes up the kthreadd_task

kthreadd_taskreset_initinit/main.c中设置.它运行 kthreadd 函数(来自 kthread.c)

kthreadd_task is set up in init/main.c in reset_init. It runs the kthreadd function (from kthread.c)

kthreadd                                                 // all in kthread.c
  -> create_kthread
    -> kernel_thread(kthread, your_kthread_create_info, ...)

kthread 函数本身就是:

kthread
  -> initialization stuff
  -> schedule() // allows you to cancel the thread before it's actually started
  -> if (!should_stop)
    -> ret = your_thread_function()
  -> do_exit(ret)

... 所以如果 your_thread_function 只是简单地返回,do_exit 将使用它的返回值被调用.无需自己动手.

... So if your_thread_function simply returns, do_exit will be called with its return value. No need to do it yourself.

这篇关于在内核中处理线程的正确方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆