【发布时间】:2021-07-01 17:18:03
【问题描述】:
我在优雅地退出我的 slurm 作业以保存数据等方面遇到问题。
我的程序中有一个信号处理程序,它设置一个标志,然后在主循环中查询该标志,然后优雅退出并保存数据。一般的方案是这样的:
#include <utility>
#include <atomic>
#include <fstream>
#include <unistd.h>
namespace {
std::atomic<bool> sigint_received = false;
}
void sigint_handler(int) {
sigint_received = true;
}
int main() {
std::signal(SIGTERM, sigint_handler);
while(true) {
usleep(10); // There are around 100 iterations per second
if (sigint_received)
break;
}
std::ofstream out("result.dat");
if (!out)
return 1;
out << "Here I save the data";
return 0;
}
不幸的是,批处理脚本很复杂,因为:
- 我想要数百个并行的、低线程数的独立任务,但我的集群每个用户只允许 16 个作业
-
srun在我的集群中总是声称一个完整的节点,即使我不想要所有的核心,所以为了在单个节点上运行多个进程,我必须使用bash
正因为如此,批处理脚本才会如此混乱(4 个进程的 2 个节点):
#!/bin/bash -l
#SBATCH -N 2
#SBATCH more slurm stuff, such as --time, etc.
srun -N 1 -n 1 bash -c '
./my_program input1 &
./my_program input2 &
wait
' &
srun -N 1 -n 1 bash -c '
./my_program input3 &
./my_program input4 &
wait
' &
wait
现在,为了传播 slurm 发送的信号,我遇到了更大的混乱(按照this 的回答,特别是双重等待):
#!/bin/bash -l
#SBATCH -N 2
#SBATCH more slurm stuff, such as --time, etc.
trap 'kill $(jobs -p) && wait' TERM
srun -N 1 -n 1 bash -c '
trap '"'"'kill $(jobs -p) && wait'"'"' TERM
./my_program input1 &
./my_program input2 &
wait
' &
srun -N 1 -n 1 bash -c '
trap '"'"'kill $(jobs -p) && wait'"'"' TERM
./my_program input3 &
./my_program input4 &
wait
' &
wait
大部分情况下它都在工作。但是,首先,我在输出结束时收到错误消息:
run: error: nid00682: task 0: Exited with exit code 143
srun: Terminating job step 732774.7
srun: error: nid00541: task 0: Exited with exit code 143
srun: Terminating job step 732774.4
...
而且,更糟糕的是,在if (!out) - errno 上实际上有 300 多个进程中有 4-6 个失败了“系统调用中断”。同样,在this 的指导下,我猜我的信号处理程序被调用了两次——第二次是在std::ofstream 构造函数下的某个系统调用期间。
现在,
- 如何摆脱 slurm 错误并真正优雅地退出?
- 我是否正确发送了两次信号?如果是,为什么,我该如何解决?
【问题讨论】:
-
srun是否保留环境变量? -
@KamilCul 我相信是的,它与 OMP_NUM_THREADS 一起使用
标签: c++ linux bash slurm signal-handling