execv返回错误时如何正确使用waitpid?
问题根源
核心原因:fork继承MySQL连接导致资源冲突
你是在fork循环执行前就创建了MySQL连接对象,fork() 会将父进程的所有资源(包括网络套接字、打开的文件描述符、C++对象实例)复制到子进程空间,MySQL连接使用的TCP套接字是内核级共享对象,父子进程会持有同一个套接字的引用:
- 当
execv()调用成功时,子进程的整个地址空间会被新的目标程序替换,原程序的C++对象析构逻辑不会执行,继承来的MySQL连接不会被主动关闭,因此父进程的连接不受影响,程序运行正常。 - 当
execv()调用失败时,子进程会继续运行原程序的逻辑,执行return EXIT_FAILURE退出时,会触发所有继承来的C++对象的析构函数,其中就包括MySQL连接对象的析构,它会直接关闭TCP套接字。此时父进程持有的连接已经被内核标记为关闭,后续操作数据库自然会抛出Lost connection to MySQL server during query错误。
附加逻辑错误
你判断子进程执行结果的代码存在逻辑错误:
if (WIFEXITED(pid_status)) { std::cout << "child process exit status: " << WEXITSTATUS(pid_status) << std::endl; // 此处错误:WIFEXITED返回非0代表子进程正常退出,你判断它等于0永远不会进入更新分支 if (WIFEXITED(pid_status) == 0) { std::cout << "updating db that file has been loaded: " << files[i].first << std::endl; } }
正确的判断应该是验证子进程的退出码是否为0:if (WEXITSTATUS(pid_status) == 0)。
修复方案
- 子进程逻辑分支开头第一行先关闭继承自父进程的MySQL连接,该操作只会减少子进程持有的套接字引用计数,不会影响父进程的连接。
- 禁止在子进程中使用父进程创建的数据库连接,如果你需要在execv失败时子进程写入失败记录,请单独创建新的数据库连接,操作完成后主动关闭再退出子进程。
- 给MySQL连接的套接字设置
FD_CLOEXEC标志,execv执行时会自动关闭该套接字,避免资源泄漏。 - 修正退出状态判断的逻辑错误。
内容的提问来源于stack exchange,提问作者Siedler
相关产品推荐
相关产品推荐

