C++中execvp未接管Stockfish子进程问题排查
问题分析与解决
你看到两次父进程输出,核心原因是execvp调用失败——execvp成功时会完全替换子进程的代码,不会执行后续的printf;但失败后子进程会继续执行main函数的剩余逻辑,导致父进程和子进程都打印了那段内容。
问题原因拆解
- execvp失败未处理退出:代码中execvp调用后没有错误处理或退出逻辑,一旦execvp失败(比如找不到文件、参数无效),子进程会继续执行
sleep(1)和printf,造成重复输出。 - Stockfish参数使用错误:
d是Stockfish的交互式命令,不是启动时的命令行参数。你把"d"作为启动参数传入,Stockfish无法识别这个参数,可能直接退出或导致execvp执行失败。 - PATH环境变量继承问题:虽然你在终端会话中export了PATH,但如果程序通过非终端方式运行(比如IDE),或者环境变量未正确继承,execvp可能找不到Stockfish可执行文件。
解决步骤
1. 添加execvp错误定位逻辑
在子进程的execvp调用后添加错误输出和退出,明确失败原因:
else if (pid == 0){ execvp(argv[0], (char* const*)argv); // 走到这里说明execvp已失败 perror("execvp failed"); _exit(EXIT_FAILURE); // 用_exit避免刷新父进程缓冲区 }
运行后会得到具体错误信息,比如No such file or directory或Permission denied,帮助快速定位问题。
2. 正确传递Stockfish的交互式命令
d是Stockfish启动后才接受的命令,需要通过标准输入发送。可以用管道实现父子进程的输入交互:
#include <iostream> #include <sys/types.h> #include <stdio.h> #include <unistd.h> #include <sys/wait.h> #include <string.h> int main(void ) { int pipefd[2]; if (pipe(pipefd) == -1) { perror("pipe failed"); return 1; } // 用绝对路径或确保PATH包含Stockfish目录 const char* argv[] = {"stockfish_15_x64_avx2", NULL}; int pid = fork(); if (pid < 0) { perror("Failed to fork"); return 1; } else if (pid == 0){ // 子进程:将标准输入重定向到管道读端 close(pipefd[1]); dup2(pipefd[0], STDIN_FILENO); close(pipefd[0]); execvp(argv[0], (char* const*)argv); perror("execvp failed"); _exit(EXIT_FAILURE); } else { // 父进程:向管道写端发送d命令,再发送quit让Stockfish退出 close(pipefd[0]); const char* cmd = "d\nquit\n"; write(pipefd[1], cmd, strlen(cmd)); close(pipefd[1]); wait(NULL); // 等待子进程结束,避免僵尸进程 } printf("Finished executing the parent process \n" " -- The child won't get here -- you will only see this once. \n"); return 0; }
3. 确保Stockfish路径可被找到
如果execvp提示找不到文件,直接使用绝对路径代替可执行文件名(注意不要用~/,execvp不会解析shell波浪号):
const char* argv[] = {"/home/你的用户名/Apps/stockfish_15_linux_x64_avx2/stockfish_15_x64_avx2", NULL};
内容的提问来源于stack exchange,提问作者Enforce
相关产品推荐
相关产品推荐

