关于OpenMPI、标准输入FD及termios使用与mpirun异常的技术咨询
OpenMPI、STDIN与termios调用失败的问题解析
这是个很典型的OpenMPI输入管理问题,我来帮你拆解清楚:
首先明确结论:OpenMPI确实会对标准文件描述符(尤其是STDIN)做特殊处理,这就是你的tcgetattr调用在mpirun环境下失败的核心原因。
1. OpenMPI对STDIN的默认处理逻辑
默认情况下,mpirun只会将rank 0进程的STDIN连接到实际的终端输入(也就是你启动mpirun时的终端)。其他所有rank的STDIN会被重定向到/dev/null(或者一个非终端的文件描述符)。
而tcgetattr是专门用于获取终端设备属性的系统调用,它只能作用于终端类型的文件描述符。当非rank0进程调用这个函数时,因为它们的STDIN不是终端,自然会返回失败。
哪怕是rank0进程,如果mpirun本身不是从终端启动(比如stdin被重定向到了普通文件),tcgetattr同样会失败——因为这时候rank0的STDIN也不是终端设备。
2. -stdin选项的作用
mpirun的-stdin选项就是用来修改上述默认行为的:
-stdin <rank>:指定将mpirun的stdin转发给特定rank的进程,只有这个指定rank的STDIN会连接到终端(或mpirun的输入源)-stdin all:让所有进程的STDIN都连接到mpirun的输入源。但要注意,这时候所有进程都会读取同一个输入流,很容易出现竞争读取的混乱情况,一般只在特定场景下使用
3. 解决你的代码问题的方案
针对你的代码,最直接的修复方式是:
- 只让rank 0进程执行终端相关的操作(比如
tcgetattr) - 在调用
tcgetattr之前,先用isatty()检查STDIN是否是终端,避免无意义的失败调用
修改后的代码示例:
#include <iostream> #include <mpi.h> #include <termios.h> #include <unistd.h> #include <cstring> #include <errno.h> int main(int argc, char** argv) { MPI_Init(&argc, &argv); int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); // 仅让rank 0处理终端属性操作 if (rank == 0) { struct termios term_attr; // 先检查STDIN是否为终端设备 if (isatty(STDIN_FILENO)) { int ret = tcgetattr(STDIN_FILENO, &term_attr); if (ret == 0) { std::cout << "Successfully got terminal attributes on rank " << rank << "\n"; // 这里可以添加你的termios后续操作 } else { std::cerr << "tcgetattr failed on rank " << rank << ": " << strerror(errno) << "\n"; } } else { std::cerr << "STDIN is not a terminal device on rank " << rank << "\n"; } } MPI_Finalize(); return 0; }
额外说明
如果你确实需要多个进程访问终端输入,除了使用-stdin all,更可靠的方式是让rank 0读取所有输入,再通过MPI消息传递将数据分发给其他进程——这样可以避免多进程读取同一输入流的混乱问题。
内容的提问来源于stack exchange,提问作者gdolle
相关产品推荐
相关产品推荐

