Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 堆上类内的Linux fork_C++_Linux_Memory Management_Fork - Fatal编程技术网

C++ 堆上类内的Linux fork

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,会发生什么 下面是一些示例代码。注意,它是从我实际做的事情

当我遇到以下情况时会发生什么情况:

类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()
处理该问题)。