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 одинаковых потоков и только хотите ждать 3-го один, но, конечно, вы можете отправить разные данных в каждый поток, с полем, описывающим его id, а затем вызывать up
или complete
, только если этот идентификатор равен 3. Это показано в примере завершения. Есть и другие способы сделать это, это всего лишь один из них.
Слово предостережения
Go прочитал еще о тех механизмах, прежде чем использовать любой из них. Есть некоторые важные детали, о которых я не писал. Также эти примеры упрощены и не проверены, они здесь, чтобы показать общую идею.
Пространство пользователя или kthread? –