如何在不等待 pthread_barrier_wait() 的情况下执行 pthread_barrier_destroy()
Posted
技术标签:
【中文标题】如何在不等待 pthread_barrier_wait() 的情况下执行 pthread_barrier_destroy()【英文标题】:How to pthread_barrier_destroy() without waiting for pthread_barrier_wait() 【发布时间】:2021-12-24 05:59:49 【问题描述】:我有一个使用屏障来同步工作线程的多线程应用程序。
在函数compute()结束时,线程被取消:
...
for(int i=0;i<p; i++)
printf("Thread %lu completed in %d passes\n",threads[i],find_tstat(threads[i])->count);
pthread_cancel(threads[i]);
printf("================================================================\n");
return a;
线程在计算过程中被中断,因此它们可能位于障碍之间。这可能是导致 pthread_barrier_destroy() 挂起的原因,因为一些 barrier_wait() 尚未返回。
问题是;即使 wait() 没有返回,我怎么还能销毁?
【问题讨论】:
您必须向我们展示compute
是如何实现的,顺便说一句。你在哪里创建你的线程,你的线程启动函数是什么以及你如何以及在哪里使用pthread_barrier_wait
。总之,你必须提供更多的代码。
@ErdalKüçük 我可以告诉你,destroy() 挂起的原因是,在某些时候,线程将在 pthread_barrier_wait() 上的所有同步之前被销毁。所以,问题是,即使 wait() 没有返回,我怎么还能销毁呢?
我已更改问题以反映这一点
使用pthread_cancel()
通常是个坏主意。最好有一种方法来通知线程它应该完全停止。例如,设置线程定期检查的原子变量。
【参考方案1】:
正如问题提出的那样:
问题是;即使 wait() 没有返回,我怎么还能销毁?
答案是“你不能”,正如your other answer 解释的那样。
但是,如果记录保持得足够好,您可以专门启动足够多的额外线程来专门在屏障处等待,以便让任何其他已经在等待的线程通过。这可能与旨在为您的线程提供干净关闭而不是被取消的代码和数据联系在一起,这也是您应该做的事情。
另一方面,使用条件变量和互斥体很容易实现自己的障碍,而且结果更加灵活。您仍然不应该取消线程,但是您可以在手动屏障处等待,例如我描述的可软取消。这是我的建议。
【讨论】:
【参考方案2】:你的问题的答案是:你不能。
-
man pthread_barrier_destroy
如果在屏障上阻塞任何线程时调用 pthread_barrier_destroy(),则结果未定义
-
man pthread_cancel
在 Linux 上,取消是使用信号实现的。
-
man pthread_barrier_wait
如果信号被传递给阻塞在屏障上的线程,则在从信号处理程序返回时,如果屏障等待尚未完成(即,如果所需数量的线程尚未到达,则线程将继续在屏障处等待)在信号处理程序执行期间的屏障处);否则,线程应从完成的屏障等待正常继续。在信号处理程序中的线程从它返回之前,未指定其他线程在全部到达屏障后是否可以继续前进。
在屏障上阻塞的线程不应阻止任何有资格使用相同处理资源的未阻塞线程最终在其执行过程中向前推进。处理资源的资格应由调度策略确定。
【讨论】:
...所以,如果您不确定确定是否要让足够多的线程到达屏障以让它们全部到达屏障,请不要让任何线程在 pthreads 屏障处等待通过。 @JohnBollinger 嗯,是的,但这是一种设计选择。这里的主要声明是,如果任何线程被阻塞在该屏障上,您就不能破坏该屏障,而不会冒未定义行为的风险。而 OP 正是想要做到这一点。以上是关于如何在不等待 pthread_barrier_wait() 的情况下执行 pthread_barrier_destroy()的主要内容,如果未能解决你的问题,请参考以下文章
如何在不关闭 Executor 的情况下等待 ThreadPoolExecutor 中的所有任务完成?