Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Linux内核中加入线程?_Linux_Multithreading_Linux Kernel - Fatal编程技术网

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

如何在Linux内核中加入线程?,linux,multithreading,linux-kernel,Linux,Multithreading,Linux Kernel,主要问题是:我们如何等待Linux内核中的线程完成?我看到一些帖子关注Linux内核中处理线程的正确方法,但我不确定如何等待主线程中的单个线程完成(假设我们需要完成线程[3],然后继续): #包括 #包括 #包括 #包括 #包括 #包括 void*func(void*arg){ //做某事 返回NULL; } int init_模块(void){ struct task_struct*线程[5]; int i; 对于(i=0;iAFAIK),内核中没有与之等价的pthread_join()。此外

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

#包括
#包括
#包括
#包括
#包括
#包括
void*func(void*arg){
//做某事
返回NULL;
}
int init_模块(void){
struct task_struct*线程[5];
int i;

对于(i=0;iAFAIK),内核中没有与之等价的
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()
}
这应该是可行的,但不是最理想的解决方案。我提到这一点是因为它是一种已知的模式,也在用户空间中使用。内核中的信号量设计用于大多数可用的情况,而这种情况下具有高争用性。因此,为这种情况创建了一种类似的优化机制

完成 您可以使用以下命令声明完成:

struct completion comp;
init_completion(&comp);
或:

然后您可以在主线程中使用
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()
}
申报完成(comp);
结构我的_数据{
int-id;
结构完成*comp;
};
int func(void*arg){
struct my_data*data=(struct my_data*)arg;
//做某事
如果(数据->id==3)
完成(数据->comp);
返回0;
}
int init_模块(void){
struct my_data*data[]=kmalloc(sizeof(struct my_data)*N,GFP_内核);
//一些初始化
对于(int i=0;icomp=&comp;
数据[i]->id=i;
kthread_run(func,(void*)数据[i],“我的线程%d”,i);
}
等待完成(&comp);//这将阻塞,直到某些线程运行完成()
}
多线程 我真的不明白为什么你会启动5个相同的线程,只想等待第三个线程,但当然你可以向每个线程发送不同的数据,并用一个字段描述它的id,然后调用
up
complete
,只要这个id等于3。这在完成示例中显示。还有其他方法可以做到这一点,我这只是其中之一

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

kthread\u stop()是内核等待线程结束的方法

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

对于单发任务,通常使用works而不是KThread更简单

编辑: 注意:只有在未释放kthread(task_struct)结构时,才能调用kthread_stop()


任何一个线程函数都应该仅在找到kthread后返回,或者应该在kthread\u stop()返回true,或者应该在启动线程之前调用get\u task\u struct()(而put\u task\u struct()应该在kthread\u stop()之后调用).

如果有一堆线程,如何将
结构完成
与单个线程关联?@krzysztof@Farhad:如果您只想等待一个线程,则不必这样做。您可以将其传递给所有线程,并在除一个线程外的所有线程中忽略它。只有此线程将调用
complete
。如果这是常规线程函数操作:
void*func(void*arg){struct completion comp;init_completion(&comp);//doing something return NULL;}
如何调用
wait_for_completion(&comp)
在主线程中,它只影响一个线程?@Farhad:这样做是错误的。你应该完全按照信号量示例中描述的那样做-你在主线程中声明完成,并将其传递给线程函数。我添加了完整的多线程和完成示例。@KrzysztofAdamski:这些同步机制都不可用确保线程函数结束是很有必要的。这是因为信号操作是在该函数内部执行的,而不是在该函数之后。因此,即使在包含函数代码的模块被卸载之后,该函数也可能被执行。这将导致崩溃。那么
join
exit在内核线程实现中?
join
由另一个线程执行,
exit
由线程本身执行。should\u stop标志实际上是对线程的提示:“其他线程等待我终止”。如果设置了该标志,则由线程检查该标志并作出反应。无法
杀死
内核线程。@Tsyvarev:正如您所写的
kthread\u stop()
将唤醒线程。这非常重要,也正是我不将其用作常规“连接”的原因替换。至少在使用
kthread\u run
时是这样。不过,它可能更适合
kthread\u create
。@KrzysztofAdamski:由于大多数等待实际上都是事件等待,所以从
kthread\u stop()
错误唤醒不是问题。从另一方面来说,
kthread\u stop()
是唯一的方法
DECLARE_COMPLETION(comp);
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()
}