Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform | страница 40
>#include
>int pthread_join(pthread_t thread, void **value_ptr);
Функции pthread_join() передается идентификатор потока, к которому вы желаете присоединиться, а также необязательный аргумент value_ptr, который может быть использован для сохранения возвращаемого присоединяемым потоком значения (Вы можете передать вместо этого параметра NULL, если это значение для вас не представляет интереса — в данном примере мы так и сделаем).
Где нам брать идентификатор потока? Мы игнорировали его в функции pthread_create(), передав NULL в качестве первого параметра. Давайте исправим нашу программу:
>int num_lines_per_cpu;
>int num_cpus;
>int main(int argc, char **argv) {
> int cpu;
> pthread_t *thread_ids;
> ... // Выполнить инициализации
> thread_ids = malloc(sizeof(pthread_t) * num_cpus);
> num_lines_per_cpu = num_x_lines / num_cpus;
> for (cpu = 0; cpu < num_cpus; cpu++) {
> pthread_create(
> &thread_ids[cpu], NULL, do_one_batch, (void*)cpu);
> }
> // Синхронизироваться с завершением всех потоков
> for (cpu = 0; cpu < num_cpus; cpu++) {
> pthread_join(thread_ids[cpu], NULL);
> }
> ... // Вывести результат
>}
Обратите внимание, что на этот раз мы передали функции pthread_create() в качестве первого аргумента указатель на >pthread_t
. Там и будет сохранен идентификатор вновь созданного потока. После того как первый цикл >for
завершится, у нас будет num_cpu работающих потоков, плюс поток, выполняющий main(). Потребление ресурсов процессора потоком main() нас мало интересует — этот поток потратит все свое время на ожидание.
Ожидание достигается применением функции pthread_join() к каждому из наших потоков. Сначала мы ждем завершения потока >thread_ids[0]
. Когда он завершится, функция pthread_join() разблокируется. Следующая итерация цикла >for
заставит нас ждать завершения потока >thread_ids[1]
, и так далее для всех num_cpus потоков.
В этот момент возникает законный вопрос: «А что если потоки завершат работу в обратном порядке?» Другими словами, если имеются 4 процессора, и по какой-либо причине поток, выполняющийся на последнем процессоре (с номером 3), завершит работу первым, затем завершится поток, выполняющийся на процессоре с номером 2, и так далее? Вся прелесть приведенной схемы заключается в том, что ничего плохого не произойдет.
Первое, что произойдет — это то, что pthread_join() блокируется на >thread_ids[0]
. Тем временем пусть завершится поток >thread_ids[3]
. Это не окажет абсолютно никакого воздействия на поток