如何在屏障处正确同步线程

Tre*_*vör 2 c unix multithreading condition-variable barrier

我遇到一个问题,我很难判断应该使用哪个同步原语。

我正在创建 n 个在内存区域上工作的并行线程,每个线程都分配给该区域的特定部分,并且可以独立于其他线程完成其任务。在某些时候,我需要收集所有线程的工作结果,这是使用屏障的一个很好的例子,这就是我正在做的事情。

我必须使用 n 个工作线程之一来收集其所有工作的结果,为此,我在线程函数中的计算代码后面添加了以下代码:

if (pthread_barrier_wait(thread_args->barrier)) {
   // Only gets called on the last thread that goes through the barrier
   // This is where I want to collect the results of the worker threads
}
Run Code Online (Sandbox Code Playgroud)

到目前为止一切顺利,但现在我陷入困境:上面的代码处于循环中,因为我希望线程在一定数量的循环旋转中再次完成工作。这个想法是,每次pthread_barrier_wait解除阻塞都意味着所有线程都已完成其工作,并且循环/并行工作的下一次迭代可以再次开始。

这样做的问题是,在其他线程再次开始处理该区域之前,不能保证结果收集器块语句的执行,因此存在竞争条件。我正在考虑使用这样的 UNIX 条件变量:

// This code is placed in the thread entry point function, inside
// a loop that also contains the code doing the parallel
// processing code.

if (pthread_barrier_wait(thread_args->barrier)) {
    // We lock the mutex
    pthread_mutex_lock(thread_args->mutex);
    collectAllWork(); // We process the work from all threads
    // Set ready to 1
    thread_args->ready = 1;
    // We broadcast the condition variable and check it was successful
    if (pthread_cond_broadcast(thread_args->cond)) {
        printf("Error while broadcasting\n");
        exit(1);
    }
    // We unlock the mutex
    pthread_mutex_unlock(thread_args->mutex);
} else {
    // Wait until the other thread has finished its work so
    // we can start working again
    pthread_mutex_lock(thread_args->mutex);
    while (thread_args->ready == 0) {
        pthread_cond_wait(thread_args->cond, thread_args->mutex);
    }
    pthread_mutex_unlock(thread_args->mutex);
}
Run Code Online (Sandbox Code Playgroud)

这有多个问题:

  • 由于某种原因,pthread_cond_broadcast永远不会解锁任何其他正在等待的线程pthread_cond_wait,我不知道为什么。
  • pthread_cond_wait如果一个线程在收集器线程广播之后会发生什么?我相信while (thread_args->ready == 0)thread_args->ready = 1阻止这种情况,但请看下一点......
  • 在下一次循环旋转时,ready仍将设置为1,因此没有线程会pthread_cond_wait再次调用。我看不到任何可以正确设置ready回的地方0:如果我在 else 块之后执行此操作,则即使我已经从该块广播pthread_cond_wait,另一个尚未 cond 等待的线程也可能会读取并开始等待。1if

请注意,我需要为此使用障碍。

我该如何解决这个问题?

Erd*_*çük 6

您可以使用两个障碍(工作和收集器):

while (true) {

    //do work

    //every thread waits until the last thread has finished its work
    if (pthread_barrier_wait(thread_args->work_barrier)) {
        //only one gets through, then does the collecting
        collectAllWork();
    }

    //every thread will wait until the collector has reached this point
    pthread_barrier_wait(thread_args->collect_barrier);

}
Run Code Online (Sandbox Code Playgroud)