如何在Linux内核中加入线程?

Far*_*had 2 linux multithreading linux-kernel

主要问题是:如何等待Linux内核中的线程完成?我已经看到了一些有关在Linux内核中处理线程的正确方法的文章,但是我不确定如何等待主线程中的单个线程完成(假设我们需要先完成thread [3]然后继续):

#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/slab.h>

void *func(void *arg) {
    // doing something
    return NULL;
}

int init_module(void) {
    struct task_struct* thread[5];
    int i;
    for(i=0; i<5; i++) {
        thread[i] = kthread_run(func, (void*) arg, "Creating thread");
    }
    return 0;
}

void cleanup_module(void) {
    printk("cleaning up!\n");
}
Run Code Online (Sandbox Code Playgroud)

Krz*_*ski 5

AFAIK pthread_join()在内核中没有等效项。另外,我觉得您的模式(启动一堆线程并仅等待其中一个线程)在内核中并不常见。话虽这么说,那里的内核确实很少有同步机制可用于实现您的目标。

请注意,这些机制将不能保证线程完成,它们只会让主线程知道它们已经完成了应做的工作。真正停止这种脚步并释放所有资源可能仍需要一些时间。

信号量

您可以创建一个锁定的信号灯,然后down在您的主线程中调用。这会让它入睡。然后up,在退出之前,您将在线程内部使用此信号量。就像是:

struct semaphore sem;

int func(void *arg) {
    struct semaphore *sem = (struct semaphore*)arg; // you could use global instead

    // do something

    up(sem);
    return 0;
}

int init_module(void) {
    // some initialization
    init_MUTEX_LOCKED(&sem);
    kthread_run(&func, (void*) &sem, "Creating thread");
    down(&sem); // this will block until thread runs up()
}
Run Code Online (Sandbox Code Playgroud)

这应该可行,但不是最佳解决方案。我之所以提及这一点,是因为它也是一种在用户空间中使用的已知模式。内核中的信号量是针对大多数情况下使用的,并且这种情况下的争用较高。因此,创建了针对这种情况优化的类似机制。

完成次数

您可以使用以下方法声明完成:

struct completion comp;
init_completion(&comp);
Run Code Online (Sandbox Code Playgroud)

要么:

DECLARE_COMPLETION(comp);
Run Code Online (Sandbox Code Playgroud)

然后你可以使用wait_for_completion(&comp);,而不是down()在主线程等待,complete(&comp);而不是up()在你的线程。

这是完整的示例:

DECLARE_COMPLETION(comp);
struct my_data {
    int id;
    struct completion *comp;
};

int func(void *arg) {
    struct my_data *data = (struct my_data*)arg;
    // doing something

    if (data->id == 3)
        complete(data->comp);

    return 0;
}

int init_module(void) {
    struct my_data *data[] = kmalloc(sizeof(struct my_data)*N, GFP_KERNEL);

    // some initialization
    for (int i=0; i<N; i++) {
        data[i]->comp = &comp;
        data[i]->id = i;
        kthread_run(func, (void*) data[i], "my_thread%d", i);
    }
    wait_for_completion(&comp); // this will block until some thread runs complete()
}
Run Code Online (Sandbox Code Playgroud)

多线程

我真的不明白为什么您要启动5个相同的线程而只想等待第3个线程,但是您当然可以向每个线程发送不同的数据,并用一个字段描述它的ID,然后调用,up或者complete仅当该ID等于3时才调用这在完成示例中显示。还有其他方法可以做到这一点,这只是其中之一。

注意事项

在使用任何一种机制之前,请先阅读有关这些机制的更多信息。我这里没有写一些重要的细节。这些示例也经过了简化而不经过测试,它们只是为了展示整体思想。

  • @Farhad:这样做是错误的方式。您应该完全按照信号量示例中的说明进行操作-您在主踏步中声明完成并将其传递给线程函数。我添加了具有多个线程和完成功能的完整示例。 (2认同)

Tsy*_*rev 5

kthread_stop()是内核等待线程结束的方法。

除了等待之外,kthread_stop()还为等待的线程设置should_stop标志,并在需要时唤醒它。它对于无限重复某些操作的线程很有用。

对于单次任务,使用 Works 通常比使用 kthreads 更简单。

编辑:注意:仅当 kthread(task_struct) 结构未释放时才能调用kthread_stop() 。

任一线程函数应仅在发现kthread_should_stop () 返回 true 后返回,或者应在启动线程之前调用get_task_struct () (并应在kthread_stop() 之后调用 put_task_struct())。