简体   繁体   English

发布C ++资源和fork-exec?

[英]Releasing C++ resources and fork-exec?

I'm trying to spawn a new process from my C++-project using fork-exec. 我正在尝试使用fork-exec从我的C ++项目中生成一个新进程。 I'm using fork-exec in order to create a bi-directional pipe to the child process. 我正在使用fork-exec来创建子进程的双向管道。 But I'm afraid my resources in the forked process won't get freed properly, since the exec-call will completely take over my process and is not going to call any destructors. 但是我担心分叉进程中的资源不会被正确释放,因为exec-call将完全接管我的进程并且不会调用任何析构函数。

I tried circumventing this by throwing an exception and calling execl from a catch block at the end of main, but this solution doesn't destruct any singletons. 我尝试通过抛出异常并在main的末尾从catch块调用execl来绕过这个,但是这个解决方案并没有破坏任何单例。

Is there any sensible way to achieve this safely? 有没有明智的方法来安全地实现这一目标? (hopefully avoiding any atExit hacks) (希望避免任何atExit黑客攻击)

Ex: The following code outputs: 例如:以下代码输出:

We are the child, gogo!
Parent proc, do nothing
Destroying object

Even though the forked process also has a copy of the singleton which needs to be destructed before I call execl. 即使分叉进程也有一个单例的副本,在我调用execl之前需要对其进行破坏。

#include <iostream>
#include <unistd.h>

using namespace std;

class Resources
{
public:
    ~Resources() { cout<<"Destroying object\n"; }
};

Resources& getRes()
{
    static Resources r1;
    return r1;
}

void makeChild(const string &command)
{
    int pid = fork();
    switch(pid)
    {
    case -1:
        cout<<"Big error! Wtf!\n";
        return;
    case 0:
        cout<<"Parent proc, do nothing\n";
        return;
    }
    cout<<"We are the child, gogo!\n";
    throw command;
}

int main(int argc, char* argv[])
{
    try
    {
        Resources& ref = getRes();
        makeChild("child");
    }
    catch(const string &command)
    {
        execl(command.c_str(), "");
    }
    return 0;
}

There are excellent odds that you don't need to call any destructors in between fork and exec . 有迹象表明,你不需要调用析构函数的任何两者之间出色的赔率forkexec Yeah, fork makes a copy of your entire process state, including objects that have destructors, and exec obliterates all that state. 是的, fork会复制整个进程状态,包括具有析构函数的对象, exec删除所有状态。 But does it actually matter? 但它真的重要吗? Can an observer from outside your program -- another, unrelated process running on the same computer -- tell that destructors weren't run in the child? 来自程序外部的观察者 - 在同一台计算机上运行的另一个不相关的进程 - 可以告诉那些析构函数不会在孩子身上运行吗? If there's no way to tell, there's no need to run them. 如果无法辨别,则无需运行它们。

Even if an external observer can tell, it may be actively wrong to run destructors in the child. 即使外部观察者可以说,在孩子身上运行析构函数也可能是错误的。 The usual example for this is: imagine you wrote something to stdout before calling fork , but it got buffered in the library and so has not actually been delivered to the operating system yet. 通常的例子是:假设你在调用fork之前向stdout写了一些东西,但是它在库中被缓存了,所以实际上还没有被传递到操作系统。 In that case, you must not call fclose or fflush on stdout in the child, or the output will happen twice! 在这种情况下,你不能在孩子的stdout上调用fclosefflush ,否则输出会发生两次! (This is also why you almost certainly should call _exit instead of exit if the exec fails.) (这也是为什么你几乎肯定应该调用_exit而不是exit如果exec失败。)

Having said all that, there are two common cases where you might need to do some cleanup work in the child. 说了这么多,有两种常见的情况,你可能需要在孩子身上做一些清理工作。 One is file descriptors ( do not confuse these with stdio FILEs or iostream objects) that should not be open after the exec . 一个是文件描述符( 不要将它们与stdio FILE或iostream对象混淆),这些描述符应该在exec之后打开。 The correct way to deal with these is to set the FD_CLOEXEC flag on them as soon as possible after they are opened (some OSes allow you to do this in open itself, but that's not universal) and/or to loop from 3 to some large number calling close ( not fclose ) in the child. 处理这些正确的方法是设置FD_CLOEXEC尽快标志上他们,他们被打开后(有些操作系统允许你这样做在open本身,但是这不是普遍的)和/或环3到一些大的在孩子中呼叫close不是 fclose )的号码。 (FreeBSD has closefrom , but as far as I know, nobody else does, which is a shame because it's really quite handy.) (FreeBSD已经closefrom ,但就我所知,没有其他人这么做,这是一种耻辱,因为它非常方便。)

The other case is system-global thread locks, which - this is a thorny and poorly standardized area - may wind up held by both the parent and the child, and then inherited across exec into a process that has no idea it holds a lock. 另一种情况是系统全局线程锁定 - 这是一个棘手且标准化程度较低的区域 - 可能会被父级和子级所占用,然后跨越exec继承到一个不知道它持有锁的进程。 This is what pthread_atfork is supposed to be for, but I have read that in practice it doesn't work reliably. 这就是pthread_atfork应该用于的目的,但我已经读过,在实践中它并不能可靠地工作。 The only advice I can offer is "don't be holding any locks when you call fork ", say sorry. 我能提供的唯一建议就是“当你拨打fork时不要拿任何锁”,对不起。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM