2011-01-11 68 views
5

我想从我的C++项目中使用fork-exec产生一个新进程。我正在使用fork-exec来为子进程创建一个双向管道。但是我担心分叉进程中的资源不会被正确释放,因为exec-call将完全接管我的进程并且不会调用任何析构函数。释放C++资源和fork-exec?

我试图通过在主月底从catch块抛出异常并调用EXECL规避这一点,但这种方法不破坏任何单身。

是否有任何明智的方法来实现这一安全? (希望避免任何atexit对黑客)

实施例:下面的代码输出:

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

即使两岔过程还具有需要之前我请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; 
} 
+1

你在谈论哪些资源?大多数文件描述符都存在于exec()中,您可以标记close-on-exec,以便内核为您关闭它们。 http://pubs.opengroup.org/onlinepubs/009695399/functions/exec.html – 2011-01-11 20:48:38

+1

顺便说一下,如果析构函数在分叉的子代以及父代中被调用,它最终会调用构造函数一次(在父代中)和析构函数两次(都在父母和孩子中)。 – 2011-01-11 20:51:23

回答

3

有,你不需要调用析构函数任何在forkexec之间的良好机会。是的,fork会复制整个进程状态,包括具有析构函数的对象,并删除所有状态。但它确实很重要吗?一个观察者可以从程序外面观察 - 另一个在同一台计算机上运行的不相关进程 - 是否告诉了解析器没有运行在孩子身上?如果没有办法说明,就没有必要运行它们。

即使外部观察者可以告诉,它可能是积极错误运行在子中的析构函数。通常的例子是:假设你在致电fork之前写了一些东西给stdout,但它被缓冲在库中,所以还没有真正传送到操作系统。在这种情况下,您一定不能致电fclosefflushstdout在子中,否则输出会发生两次! (这也是为什么你几乎可以肯定应该调用_exit而不是exit如果exec失败。)

说了这么多,还有,你可能需要做一些清理工作,在儿童中的两种情况。一种是文件描述符(请勿将与stdio FILE或iostream对象混淆),在exec之后不应该打开它们。处理这些正确的方法是,以尽快之后他们打开(某些操作系统允许你这样做在open本身,但这不是普遍的)和/或环3设置FD_CLOEXEC标志对他们一些大号呼叫close不是fclose)在孩子。 (FreeBSD有closefrom,但据我所知,没有人会这样做,这是一个耻辱,因为它真的很方便。)

另一种情况是系统全局线程锁,它是一个棘手的标准区域 - 可能最终由父母和孩子共同拥有,然后通过exec继承,这个过程不知道它拥有锁定。这是pthread_atfork应该是,但我已经读过,实际上它不能可靠地工作。我可以提供的唯一建议是“当你打电话给fork时不要拿着任何锁,”对不起。