pthread_barrier没有表现出我的期望

时间:2018-02-22 19:34:18

标签: c multithreading pthreads

我在C ++中运行它,但是我认为相同的代码可以在C中运行。我对障碍的理解是,当你使用pthread_barrier_init()时,你给它一个数字。该数字表示在任何线程被解除阻塞之前必须调用pthread_barrier_wait()的线程数。所以基本上如果数字是4并且你有3个线程到目前为止执行了wait()行,那么所有3个线程都将被阻塞,直到第4个线程出现并调用pthread_barrier_wait()。

我试图让所有线程同时开始执行。

#include <pthread.h>
#include <stdio.h>

void* thread_func(void* args) {
    pthread_barrier_t *barrier = (pthread_barrier_t*)args;
    printf("waiting for barrier\n");
    pthread_barrier_wait(barrier);
    printf("passed barrier\n");

    return NULL;
}

int main() {
    int const num_threads = 4;
    pthread_t threads[num_threads];
    pthread_barrier_t *barrier;

    pthread_barrier_init(barrier, NULL, num_threads);

    int i;
    for (i = 0; i < num_threads; i++) {
        pthread_create(&threads[i], NULL, thread_func, (void*)barrier);
    }

    for (i = 0; i < num_threads; i++) {
        pthread_join(threads[i], NULL);
    }

    return 0;
}

我收到的输出:

waiting for barrier
waiting for barrier
waiting for barrier
passed barrier
passed barrier
passed barrier
waiting for barrier
passed barrier

输出我期望:

waiting for barrier
waiting for barrier
waiting for barrier
waiting for barrier
passed barrier
passed barrier
passed barrier
passed barrier

另一个非常奇怪的事情是,在我的pthread_barrier_init(barrier,NULL,num_threads)调用中,我可以将数字更改为(num_threads + 40)并且程序仍然运行。我认为在这种情况下,在这种情况下,所有的线程都将永远坐在他们的wait()调用中,因为永远不会有num_threads + 40个线程在等待。

我错过了什么?

2 个答案:

答案 0 :(得分:4)

pthread_barrier_t *barrier;
pthread_barrier_init(barrier, NULL, num_threads);

所以barrier是一个永远不会指向任何东西的指针。您永远不会为barrier分配值,但会将其值传递给pthread_barrier_init。所以pthread_barrier_init获取垃圾值,你的线程也是如此。

在某个地方,你需要创建一个实际的障碍,而不仅仅是一个指针。

你可以这样做:

pthread_barrier_t actual_barrier;
pthread_barrier_t *barrier = &actual_barrier;
pthread_barrier_init(barrier, NULL, num_threads);

这实际上会创建一个障碍并将其地址传递给pthread_barrier_init,因此可以初始化您实际创建的障碍。

答案 1 :(得分:1)

@DavidSchwartz给出的答案增加了一条额外的行,以使指针形式清楚如何需要指向pthread_barrier_t的实际实例。但是,对于非常本地化的用法,更典型的是:

pthread_barrier_t barrier;
pthread_barrier_init(&barrier, NULL, num_threads);