可以在Linux上实现正确的故障安全流程共享障碍吗?

R..*_*R.. 11 c linux posix pthreads barrier

在过去的一个问题中,我询问了如何在没有破坏竞赛的情况下实施pthread障碍:

一旦pthread_barrier_wait返回,障碍如何可以销毁?

并且从迈克尔伯尔那里得到了一个完美的流程局部障碍解决方案,但却因流程共享障碍而失败.我们后来研究了一些想法,但从未得出令人满意的结论,甚至没有开始陷入资源失败的情况.

是否有可能在Linux上构建满足这些条件的障碍:

  • 进程共享(可以在任何共享内存中创建).
  • 在屏障等待函数返回后立即从任何线程中取消映射或销毁屏障是安全的.
  • 由于资源分配失败,无法失败.

迈克尔尝试解决流程共享案例(参见链接问题)有一个不幸的特性,即必须在等待时间分配某种系统资源,这意味着等待可能会失败.并且不清楚当障碍等待失败时调用者可以合理地做什么,因为屏障的整个点是在其余N-1线程到达之前继续进行是不安全的......

内核空间解决方案可能是唯一的方法,但即使这很困难,因为信​​号可能会中断等待而没有可靠的方法来恢复它...

R..*_*R.. 1

在与 bdonlan 在 SO 聊天上进行了长时间的讨论之后,我想我有一个解决方案。基本上,我们将问题分解为两个自同步释放问题:销毁操作和取消映射。

处理破坏很简单:只需让pthread_barrier_destroy函数等待所有服务员停止检查屏障即可。这可以通过在屏障中设置使用计数、在进入/退出等待函数时自动递增/递减以及让销毁函数旋转等待计数达到零来完成。(如果您在使用计数的高位或类似位置粘贴一个服务员标志,也可以在这里使用 futex,而不仅仅是旋转。)

处理取消映射也很容易,但不是本地的:通过向系统调用包装器添加锁定,确保在屏障等待者退出过程中不会发生munmapmmap带有标志的情况。MAP_FIXED这需要一种特殊的读写锁。最后一个到达屏障的等待者应该获取munmaprw-lock 上的读锁,该锁将在最后一个等待者退出时释放(当递减用户计数导致计数为 0 时)。munmap并且mmap可以通过使编写器锁递归来使其可重入(正如某些程序可能期望的那样,即使 POSIX 不需要它)。实际上,一种读者和写者完全对称的锁,并且每种类型的锁都排除相反类型的锁,但不包括相同类型的锁,应该效果最好。