C++ 堆上类内的Linux fork
当我遇到以下情况时会发生什么情况: 类A:保留动态分配的对象B。它将创造和摧毁这些 类B:有一个由A调用的execute函数。execute will fork()子类将使用execvp运行另一个进程。但是,可以设置一个标志,以便父级不会等待子级(允许它在后台运行) 我的问题是,fork在这种情况下做了什么?我知道孩子有一份完整的家长流程副本,但我有点困惑。那么,这是否意味着子进程有自己的对象A,其中包含B?如果B没有等待,但A删除了B,会发生什么 下面是一些示例代码。注意,它是从我实际做的事情中简化出来的C++ 堆上类内的Linux fork,c++,linux,memory-management,fork,C++,Linux,Memory Management,Fork,当我遇到以下情况时会发生什么情况: 类A:保留动态分配的对象B。它将创造和摧毁这些 类B:有一个由A调用的execute函数。execute will fork()子类将使用execvp运行另一个进程。但是,可以设置一个标志,以便父级不会等待子级(允许它在后台运行) 我的问题是,fork在这种情况下做了什么?我知道孩子有一份完整的家长流程副本,但我有点困惑。那么,这是否意味着子进程有自己的对象A,其中包含B?如果B没有等待,但A删除了B,会发生什么 下面是一些示例代码。注意,它是从我实际做的事情
class B;
class A
{
public:
void addAction( const std::string &name )
{
_bq.push( new B( name ) );
}
void doActions( bool wait = true )
{
while ( !_bq.empty() )
{
B* b = _bq.front();
b->execute( wait );
_bq.pop();
delete b;
}
}
~A() { //omitted, but just deletes everything in queue }
private:
std::queue<B*> _bq;
};
class B
{
public:
B( const std::string &name )
{
args.push_back( name.c_str() );
args.push_back( NULL );
}
void execute( bool waitForChild )
{
pid_t pid = fork();
if ( pid != 0 )
{
if (waitForChild)
{
int status;
wait( &status );
// check status...
}
}
else
{
execvp( args[0], const_cast<char**>( &args[0] ) );
// problem
exit( 100 );
}
}
private:
std::vector<char*> args;
};
B类;
甲级
{
公众:
void addAction(const std::string和name)
{
_推送(新B(名称));
}
无效操作(bool wait=true)
{
而(!\u bq.empty())
{
B*B=_bq.front();
b->执行(等待);
_bq.pop();
删除b;
}
}
~A(){//省略,但只删除队列中的所有内容}
私人:
std::队列_bq;
};
B类
{
公众:
B(常量标准::字符串和名称)
{
args.push_back(name.c_str());
args.push_back(空);
}
无效执行(bool waitForChild)
{
pid_t pid=fork();
如果(pid!=0)
{
if(waitForChild)
{
智力状态;
等待(&状态);
//检查状态。。。
}
}
其他的
{
execvp(args[0],const_cast(&args[0]);
//问题
出口(100);
}
}
私人:
std::向量args;
};
子进程与父进程完全分离,并且具有父进程变量的完整副本。当子执行(调用<代码> ExcEvE)(<代码> >或其一个亲属)时,不执行C++析构函数。但是,这对父进程没有任何影响
因此,孩子和过程之间没有干扰。父母是否等待孩子并不重要。一旦fork()
返回(成功)到父进程,子进程将独立运行,父进程对分配的变量所做的任何操作都不会影响子进程
如果您真的很努力,通过placement
new
将共享内存和变量分配到共享内存中,并且如果孩子在调用execvp()
之前清理共享内存中的变量,或者其他类似的牵强但并非不可能的场景,那么孩子和父母就不是完全独立的了。然而,如果你在做这么复杂的事情,你可能也不会问这个问题。当你分叉你的流程时,你会得到整个流程的副本(尽管它通常是使用写时拷贝实现的),我所说的“完整拷贝”,是指整个拷贝;包括为该进程分配的各种页面,因此逻辑上有一个完整的堆的另一个副本,对于每个线程,有一个该线程及其关联堆栈的副本,所以是的,有两个a和B的副本
然而,当涉及到分叉时,一个更紧迫的问题是线程会发生什么?或者,如果为一个线程添加一个“atfork”钩子,会发生什么?这是fork+exec在UNIX环境中使用起来相当困难的几种方法之一。通常,最好使用库或使用
popen
,一次性解决此问题,而不是到处尝试多次解决此问题。一个fork会将堆与其余的进程数据一起复制。您的本地wait变量隐藏了wait函数。谢谢,这不是我的确切代码,但这是一个很好的观点,当你说在孩子中执行“没有C++析构函数”时,这是否意味着子进程中的类A对象将不会清理它创建的B对象?这是一个问题,还是因为进程终止时它才被清理出来就可以了?@Matt:child中的A对象没有机会清理B对象。它通常是好的;如果不是,则在执行新流程之前,必须在子流程中执行大量工作。请注意,在运行析构函数的意义上,A对象和B对象都不会被“清理”。当新的可执行文件替换原始文件(在子进程中)时,它们就不再存在了。当新进程终止时,任何O/S资源(文件描述符等)都将被释放(除非它们上有FD_CLOEXEC标志),但子进程无论如何不持有锁(fork()
处理该问题)。