在c++中正确退出分叉进程
Correctly exit forked process in C++
阅读如何结束c++代码的答案,我了解到从c++代码中调用exit
是不好的。但是,如果我派生了一个子进程,它必须在某处结束,并且位于调用堆栈的深处,以至于无法将其退出代码传递给main,该怎么办?
我找到了一些替代方法来做到这一点——不可否认,这已经变得有点长了,但请耐心听我说:
#include <sys/stat.h>
#include <unistd.h>
#include <sys/wait.h>
#include <cstdlib>
#include <memory>
#include <string>
#include <iostream>
thread_local char const* thread_id{"main"};
struct DtorTest {
std::string where{};
DtorTest(void) = default;
DtorTest(std::string _where) : where{std::move(_where)} {}
~DtorTest(void) {
std::cerr << __func__ << " in " << thread_id << ", origin " << where << std::endl;
}
};
std::unique_ptr< DtorTest > freeatexit{nullptr};
pid_t
fork_this(pid_t (*fork_option)(void))
{
DtorTest test(__func__);
return fork_option();
}
pid_t
fork_option0(void)
{
pid_t pid;
if ((pid = fork()))
return pid;
thread_id = "child";
DtorTest test(__func__);
std::exit(EXIT_SUCCESS);
}
pid_t
fork_option1(void)
{
pid_t pid;
if ((pid = fork()))
return pid;
thread_id = "child";
DtorTest test(__func__);
std::_Exit(EXIT_SUCCESS);
}
pid_t
fork_option2(void)
{
pid_t pid;
if ((pid = fork()))
return pid;
{
thread_id = "child";
DtorTest test(__func__);
}
std::_Exit(EXIT_SUCCESS);
}
pid_t
fork_option3(void)
{
pid_t pid;
if ((pid = fork()))
return pid;
thread_id = "child";
DtorTest test(__func__);
throw std::exception();
}
int main(int argc, char const *argv[])
{
int status;
const int option = (argc > 1) ? std::stoi(argv[1]) : 0;
pid_t pid;
freeatexit = std::unique_ptr< DtorTest >(new DtorTest(__func__));
switch (option) {
case 0:
pid = fork_this(fork_option0);
break;
case 1:
pid = fork_this(fork_option1);
break;
case 2:
pid = fork_this(fork_option2);
break;
case 3:
try {
pid = fork_this(fork_option3);
} catch (std::exception) {
return EXIT_SUCCESS;
}
break;
case 4:
try {
pid = fork_this(fork_option3);
} catch (std::exception) {
std::_Exit(EXIT_SUCCESS);
}
break;
default:
return EXIT_FAILURE;
}
waitpid(pid, &status, 0);
return status;
}
<标题>选项0 可能是最坏的:
./a.out 0
~DtorTest in main, origin fork_this
~DtorTest in child, origin main
~DtorTest in main, origin main
问题是,fork_option0
中test
的析构函数没有被调用,因为std::exit简单地忽略了任何具有自动存储的对象。unique_ptr
析构函数被调用两次。
./a.out 1
~DtorTest in main, origin fork_this
~DtorTest in main, origin main
fork_option1
中的析构函数也有同样的问题,因为std::_Exit也忽略了自动存储。至少unique_ptr
析构函数只被调用一次。
./a.out 2
~DtorTest in main, origin fork_this
~DtorTest in child, origin fork_option2
~DtorTest in main, origin main
<标题>选项3 这是最接近main通知返回的,但是它有几个问题: 虽然 比选项3稍微好一点,因为没有了 那么退出/结束子进程的正确方法是什么? 从上面的实验来看,选项2似乎效果最好。然而,我可能错过了./a.out 3
~DtorTest in main, origin fork_this
~DtorTest in child, origin fork_option3
~DtorTest in child, origin fork_this
~DtorTest in child, origin main
~DtorTest in main, origin main
fork_option3
中的析构函数被正确调用,但是发生了两个双自由度。首先是unique_ptr
,其次是fork_this
中的对象。./a.out 4
~DtorTest in main, origin fork_this
~DtorTest in child, origin fork_option3
~DtorTest in child, origin fork_this
~DtorTest in main, origin main
unique_ptr
的double free。然而,fork_this
中的对象仍然是双自由的。std::_Exit
的其他问题(参见如何结束c++代码)
这是fork
的传统模式。
#include <sys/stat.h>
#include <unistd.h>
#include <sys/wait.h>
#include <cstdlib>
#include <iostream>
#include <fstream>
struct DtorTest {
~DtorTest(void) { std::cout << "d'tor never runsn"; }
};
int
child(void)
{
// only child
DtorTest dtortest; // D'tor never runs
std::ofstream fout("inchild.txt"); // file not flushed
fout << "this is in the childn";
return 0;
}
int
main(void)
{
pid_t pid;
if ((pid = fork()))
int status;
waitpid(pid, &status, 0);
return status;
} else {
return child();
}
}
不要对系统包含文件使用extern "C"
。如果您需要这样做,那么您一定使用了一个古老的编译器,并且所有的赌注都取消了。
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 创建LinkedList退出,返回代码为-11(SIGSEGV)
- 当我在main中声明了我的2d数组时,为什么我的程序会退出
- 如何让LLDB在成功时退出,在失败时等待
- C++控制台应用程序阻止退出
- 程序在执行程序的其余部分之前退出
- 构造函数在退出函数时无法初始化一个参数
- 为什么异常不退出程序?
- 我不断收到 [错误] ID 返回 1 退出状态错误,但看不到问题所在
- 退出简单while循环时出现问题
- 使用vscode调试时,GDB意外退出
- pclose() 不会给我进程退出代码
- 为什么系统函数总是在C++中返回已转移的退出状态?
- C++从另一个函数退出函数
- C++ 中的编译错误:未定义对"主"的引用 collect2:错误:ld 返回 1 个退出状态
- C++逗号分隔的输入数组代码过早退出
- Netbeans 10:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)
- 在分叉父进程退出后跳回子进程
- Poco 异步通道不会在分叉进程退出时退出
- 在c++中正确退出分叉进程