Спасибо всем за отличные ответы!Было много разговоров об использовании барьеров памяти и т. Д., Поэтому я решил опубликовать ответ, который правильно показал бы, как они используются для этого.
#define NUM_THREADS 5
unsigned int thread_count;
void *threadfunc(void *arg) {
printf("Thread %p running\n",arg);
sleep(3);
printf("Thread %p exiting\n",arg);
__sync_fetch_and_sub(&thread_count,1);
return 0L;
}
int main() {
int i;
pthread_t thread[NUM_THREADS];
thread_count=NUM_THREADS;
for (i=0;i<NUM_THREADS;i++) {
pthread_create(&thread[i],0L,threadfunc,&thread[i]);
}
do {
__sync_synchronize();
} while (thread_count);
printf("All threads done\n");
}
Обратите внимание, что макросы __sync являются «нестандартными» внутренними макросами GCC.LLVM также поддерживает их, но если вы используете другой компилятор, вам, возможно, придется сделать что-то другое.
Еще одна важная вещь, на которую следует обратить внимание: зачем вам записывать все ядро или тратить «половину» вращения ЦП?в тесном цикле опроса, просто ожидая, пока другие закончат - когда вы могли бы легко заставить его работать?Следующий мод использует начальный поток для запуска одного из рабочих, а затем дождитесь завершения остальных:
thread_count=NUM_THREADS;
for (i=1;i<NUM_THREADS;i++) {
pthread_create(&thread[i],0L,threadfunc,&thread[i]);
}
threadfunc(&thread[0]);
do {
__sync_synchronize();
} while (thread_count);
printf("All threads done\n");
}
Обратите внимание, что мы начинаем создавать потоки, начиная с "1" вместо "0", затемнапрямую запустить «поток 0», ожидая завершения всех потоков после его завершения.Мы передаем & thread [0] к нему для согласованности (хотя здесь это бессмысленно), хотя в действительности вы, вероятно, передадите свои собственные переменные / контекст.