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()
}
这应该可行,但不是最佳解决方案。我提到这一点是因为它是一种在用户空间中也使用的已知模式。内核中的信号量是为大多数可用的情况而设计的,并且这种情况具有很高的争用性。因此创建了针对这种情况优化的类似机制。
完成次数
您可以使用以下方式声明完成:
struct completion comp;
init_completion(&comp);
或:
DECLARE_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 = ∁
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()
}
多线程
我真的不明白为什么你会启动 5 个相同的线程并且只想等待第三个线程,但当然你可以向每个线程发送不同的数据,并使用一个描述它的 id 的字段,然后调用 up 或complete 仅当此 id 等于 3 时。如完成示例中所示。还有其他方法可以做到这一点,这只是其中之一。
注意事项
在使用其中任何一个之前,请先阅读有关这些机制的更多信息。有一些重要的细节我没有在这里写。这些示例也经过简化且未经测试,仅用于展示总体思路。