OpenMP 并行程序中的信号处理
我有一个使用 POSIX 计时器的程序 (timer_create()
)。本质上,程序设置一个计时器并开始执行一些冗长(可能是无限的)计算。当计时器到期并且调用信号处理程序时,处理程序会打印已计算出的最佳结果并退出程序。
我考虑使用 OpenMP 并行计算,因为它应该加快计算速度。
在 pthreads 中,有一些特殊的函数,例如为我的线程设置信号掩码等。 OpenMP 是否提供此类控制,或者我是否必须接受信号可以传递到 OpenMP 创建的任何线程的事实?
另外,如果我当前位于代码的并行部分并且调用了我的处理程序,它仍然可以安全地终止应用程序 (exit(0);
) 并执行诸如锁定 OpenMP 锁之类的操作吗?
I have a program which uses POSIX timer (timer_create()
). Essentially the program sets a timer and starts performing some lengthy (potentially infinite) computation. When the timer expires and a signal handler is called, the handler prints the best result yet that has been computed and quits the program.
I consider doing the computation in parallel using OpenMP, because it should speed it up.
In pthreads, there are special functions for example for setting signal masks for my threads or so. Does OpenMP provide such control, or do I have to accept the fact that the signal can be delivered to any of the threads OpenMP creates?
Also, in case I am currently in a parallel section of my code and my handler is called, can it still safely kill the application (exit(0);
) and do things like locking OpenMP locks?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这有点晚了,但希望这个示例代码能够帮助处于类似位置的其他人!
正如 osgx 提到的,OpenMP 在信号问题上保持沉默,但由于 OpenMP 通常在 POSIX 系统上使用 pthread 实现,因此我们可以使用 pthread 信号方法。
对于使用 OpenMP 的繁重计算,可能只有少数位置可以真正安全地停止计算。因此,对于您想要获得过早结果的情况,我们可以使用同步信号处理来安全地做到这一点。另一个优点是,这让我们可以接受来自特定 OpenMP 线程的信号(在下面的示例代码中,我们选择主线程)。在捕获信号时,我们只需设置一个标志来指示计算应该停止。然后,每个线程应确保在方便时定期检查此标志,然后结束其分担的工作负载。
通过使用这种同步方法,我们允许计算优雅地退出,并且对算法的更改非常小。另一方面,所需的信号处理程序方法可能并不合适,因为可能很难将每个线程的当前工作状态整理成一致的结果。不过,同步方法的一个缺点是计算可能需要相当长的时间才能停止。
信号检查装置由三部分组成:
有一些重要的性能考虑因素和警告:
omp for
循环无法打破1,因此您必须旋转剩余的迭代或使用更基本的 OpenMP 原语重写循环。常规循环(例如外部并行循环的内部循环)可以很好地分解。下面是示例代码:
如果使用 C++,您可能会发现以下类很有用...
然后,
calculate()
的阻塞部分可以替换为Unterminable unterm();
,以及if ((sigcaught = unterm.poll()) > 0) {...}
的信号检查部分。当unterm
超出范围时,会自动执行解除信号阻塞操作。1 这并不完全正确。 OpenMP 对以取消点<的形式执行“并行中断”提供有限支持/a>.如果您选择在并行循环中使用取消点,请确保您确切知道隐式取消点的位置,以便确保计算数据在取消时保持一致。
2 2nowait。
This is a bit late, but hopefully this example code will help others in a similar position!
As osgx mentioned, OpenMP is silent on the issue of signals, but as OpenMP is often implemented with pthreads on POSIX systems we can use a pthread signal approach.
For heavy computations using OpenMP, it is likely that there are only a few locations where computation can actually be safely halted. Therefore, for the case where you want to obtain premature results we can use synchronous signal handling to safely do this. An additional advantage is that this lets us accept the signal from a specific OpenMP thread (in the example code below, we choose the master thread). On catching the signal, we simply set a flag indicating that computation should stop. Each thread should then make sure to periodically check this flag when convenient, and then wrap up its share of the workload.
By using this synchronous approach, we allow computation to exit gracefully and with very minimal change to the algorithm. On the other hand, a signal handler approach as desired may not be appropriate, as it would likely be difficult to collate the current working states of each thread into a coherent result. One disadvantage of the synchronous approach though is that computation can take a noticeable amount of time to come to a stop.
The signal checking apparatus consists of three parts:
omp parallel
region so that each OpenMP thread (pthread) will inherit this same blocking behaviour.sigtimedwait
for this, but some systems (e.g. MacOS) don't support this. More portably, we can usesigpending
to poll for any blocked signals and then double check that the blocked signals are what we're expecting before accepting them synchronously usingsigwait
(which should return immediately here, unless some other part of the program is creating a race condition). We finally set the relevant flag.There are some important performance considerations and caveats:
omp for
loops cannot be broken out of1, and so you must either spin for the remainder of the iterations or rewrite the loop using more basic OpenMP primitives. Regular loops (such as inner loops of an outer parallel loop) can be broken out of just fine.Here is the example code:
If using C++, you may find the following class useful...
The blocking part of
calculate()
can then be replaced byUnterminable unterm();
, and the signal checking part byif ((sigcaught = unterm.poll()) > 0) {...}
. Unblocking the signals is automatically performed whenunterm
goes out of scope.1 This is not strictly true. OpenMP supports limited support for performing a 'parallel break' in the form of cancellation points. If you choose to use cancellation points in your parallel loops, make sure you know exactly where the implicit cancellation points are so that you ensure that your computation data will be coherent upon cancellation.
2 Personally, I keep a count of how many threads have completed the for loop and, if the master thread completes the loop without catching a signal, it keeps polling for signals until either it catches a signal or all threads complete the loop. To do this, make sure to mark the for loop
nowait
.OpenMP 3.1 标准没有提及信号。
据我所知,Linux/UNIX 上每个流行的 OpenMP 实现都是基于 pthread 的,因此 OpenMP 线程是 pthread 的线程。并且适用 pthread 和信号的通用规则。
没有任何特定控制;但你可以尝试使用pthread的控制。唯一的问题是知道使用了多少 OpenMP 线程以及在哪里放置控制语句。
默认情况下,是的,它将被传递到任何线程。
有关信号处理程序的通常规则仍然适用。信号处理程序中允许的函数列于 http://pubs.opengroup.org/ onlinepubs/009695399/functions/xsh_chap02_04.html (在页面末尾)
并且不允许
printf
(write
是)。如果您知道在发出信号时 printf 未被任何线程使用(例如,并行区域中没有 printf),则可以使用 printf。是的,可以:处理程序允许
abort()
和_exit()
。当任何线程
退出
或中止
时,Linux/Unix将终止所有线程。你不应该这样做,但是如果你知道这个锁在信号处理程序运行时不会被锁定,你可以尝试这样做。
!!更新
有一个采用 OpenMP 信令的示例 http://www.cs.colostate .edu/~cs675/OpenMPvsThreads.pdf(“OpenMP 与 C/C++ 中的线程处理”)。简而言之:在处理程序中设置一个标志,并在每次第 N 次循环迭代时在每个线程中添加对此标志的检查。
OpenMP 3.1 standard says nothing about signals.
As I know, every popular OpenMP implementation on Linux/UNIX is based on pthreads, so OpenMP thread is pthread's thread. And generic rules of pthreads and signals apply.
No any specific control; but you can try to use pthread's control. Only problem is to know how much OpenMP threads are used and where to place controlling statement.
By default, yes, it will be delivered to any thread.
Usual rules about signal handler still applies. Functions allowed in signal handler are listed at http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html (at the end of page)
And
printf
is not allowed (write
is). You can use printf if you know that at the moment of signal printf is not used by any thread (e.g. you has no printf in parallel region).Yes it can:
abort()
and_exit()
are allowed from handler.Linux/Unix will terminate all threads when any thread does
exit
orabort
.You should not, but if you know that this lock will be not locked at the time of signal handler run, you can try to do this.
!! UPDATE
There is an example of adopting signalling to OpenMP http://www.cs.colostate.edu/~cs675/OpenMPvsThreads.pdf ("OpenMP versus Threading in C/C++"). In short: set a flag in handler and add checks of this flag in every thread at every Nth loop iteration.