【问题标题】:When is it safe to destroy a pthread barrier?什么时候破坏 pthread 屏障是安全的?
【发布时间】:2010-10-26 20:13:31
【问题描述】:

如果我有一个初始化的 pthread_barrier_t,什么时候可以安全地销毁它?下面的例子安全吗?

pthread_barrier_t barrier;
...
int rc = pthread_barrier_wait(b);
if (rc != PTHREAD_BARRIER_SERIAL_THREAD && rc != 0){
  perror("pthread_barrier_wait");
  exit(1);
}

if (id == 0){
  if(pthread_barrier_destroy(&(threads[t_root].info.tmp_barrier))){
    perror("pthread_barrier_destroy");
    exit(1);
  }
}

【问题讨论】:

    标签: c multithreading posix pthreads


    【解决方案1】:

    pthread_barrier_wait() 返回后,所有线程都将遇到障碍并继续进行。由于只有一个线程被赋予了PTHREAD_BARRIER_SERIAL_THREAD 返回值,因此可以安全地使用它来有条件地包装销毁代码,如下所示:

    int rc = pthread_barrier_wait(&b)
    if ( rc == PTHREAD_BARRIER_SERIAL_THREAD )
    {
        pthread_barrier_destroy(&b);
    }
    

    另外,请注意,如果屏障正在使用中(即另一个线程调用了 pthread_barrier_wait()),pthread_barrier_destroy() 将返回 EBUSY 的结果。

    【讨论】:

    • 你回答的最后一句话是假的。根据 POSIX,它是 UB:“如果在屏障上阻塞任何线程时调用 pthread_barrier_destroy(),或者如果使用未初始化的屏障调用此函数,则结果未定义。” (pubs.opengroup.org/onlinepubs/9699919799/functions/…)
    【解决方案2】:

    接受的答案不正确。 PTHREAD_BARRIER_SERIAL_THREAD 的返回值并不意味着破坏屏障是安全的。

    在破坏屏障之前,您需要额外的同步。

    问题是在其他线程正在离开屏障的过程中可能会发生销毁调用。由于 futex 系统调用可能有“错误唤醒”,这些线程需要检查屏障的状态。如果屏障使用的内存从它们下面释放出来,则会发生未定义的行为。

    因此,销毁线程需要等到所有其他线程完成退出屏障。为了实现这一点,需要额外的同步。 Source with alternative implementation using pthread_cond

    在此问题中,用户执行的逻辑与您在示例代码中的逻辑相同。 https://groups.google.com/forum/#!topic/thread-sanitizer/81idLTirikQ

    【讨论】:

    • 回顾一下,返回 PTHREAD_BARRIER_SERIAL_THREAD 并不能保证所有其他线程都已退出屏障——您不知道自己是最后一个离开的线程。如果任何其他线程仍在屏障“内部”,则销毁它是不安全的。