C++ 实时系统的两阶段构建

C++ 实时系统的两阶段构建,c++,class,constructor,real-time,C++,Class,Constructor,Real Time,我正在开发一个实时系统,我正在讨论课程的设计。 具体来说,我无法决定是否使用两阶段构造来构建“重”类 一方面,调用“重”类的构造函数在运行时可能是一个主要的瓶颈,它可以避免我创建类和分配用户可能不会使用的功能的内存 另一方面,考虑到我们试图访问某个能力时的情况,两阶段构造可能会在执行过程中产生意外,但我们不能,因为它没有初始化,突然我们需要在使用之前完全构建它 我倾向于采用两阶段施工方法。我喜欢听到的是在实时系统上进行两阶段施工的利弊。如果有更好的方法 这里有一个重载类的代码示例(我的类肯定不会

我正在开发一个实时系统,我正在讨论课程的设计。
具体来说,我无法决定是否使用两阶段构造来构建“重”类

一方面,调用“重”类的构造函数在运行时可能是一个主要的瓶颈,它可以避免我创建类和分配用户可能不会使用的功能的内存

另一方面,考虑到我们试图访问某个能力时的情况,两阶段构造可能会在执行过程中产生意外,但我们不能,因为它没有初始化,突然我们需要在使用之前完全构建它

我倾向于采用两阶段施工方法。我喜欢听到的是在实时系统上进行两阶段施工的利弊。如果有更好的方法

这里有一个重载类的代码示例(我的类肯定不会这样,但它展示了我的想法):

如果我们有两个实体,则两阶段方法的主“pro”。第一个提供接口IFirst并需要外部ISecond实现。第二个函数提供IsSecond,并依次要求IFirst。如果没有两相初始,这是“鸡和蛋”无法解决的问题

根据重对象与有限范围(如实时/移动/嵌入式)的不同,尽可能使对象变薄和懒惰可能是值得的。调用方可能负责在使用某些功能之前提供一系列init调用,以确保在启动之前所有内容都已正确初始化。

这是AGC,阿波罗制导计算机,用于阿波罗指挥舱和登月舱。以几乎导致阿波罗11号着陆被擦洗而闻名。在降落到月球表面的中间,这台计算机在一个实时错误上崩溃了。好几次。产生系统错误1201(执行溢出-无空白区域)和系统错误1202(执行溢出-无核心集)。阿姆斯特朗和奥尔德林只看到了数字,照片右侧的用户界面设备太原始,无法显示字符串。是导航控制器知道这些数字的含义(他们在训练时从未见过错误),并且知道系统可以从中恢复。他通过试一试拯救了这次登陆,并因此获得了总统自由勋章

这可能就是你的问题所要问的,尽管我们可以非常确定你没有试图让火箭着陆。“实时”一词过去在软件工程中有很好的定义,但它被金融业搞糊涂了。在阿波罗11号中,这意味着对外部事件的最大响应时间有一个非常严格的上限。火箭需要一个这样的系统,有时候调整喷嘴的时候不能太迟,一旦迟了就会产生十亿美元的火球。金融业劫持它意味着一个任意快速的系统,迟到有时不会让机器蒸发,尽管它会增加交易损失的几率。他们可能认为这也是一场灾难:

您使用的内存分配器非常重要,问题中也没有定义。我假设你的程序运行在一个按需分页的虚拟内存操作系统上。这并不完全是实时系统的理想环境,但真正的实时操作系统却非常普遍

两阶段构造是一种用于处理初始化失败的技术,构造函数中抛出的异常很难处理,析构函数将不会运行,因此如果您在构造函数中进行分配,而没有使构造函数足够聪明来处理灾难,则会导致资源泄漏。另一种方法是稍后在成员函数中执行,根据需要惰性地分配

因此,您担心的是,延迟分配会妨碍系统的响应能力。生成系统错误1201

事实上,这并不是Linux或Windows等按需分页虚拟内存操作系统的主要问题。这些操作系统上的内存分配器速度很快,它只分配虚拟内存。这不需要任何费用,它是虚拟的。当您实际开始使用分配的内存时,真正的成本会在以后出现。其中“需求”页面的“需求”起作用。寻址数组元素将产生页面错误,迫使操作系统将寻址的虚拟内存页面映射到RAM中。这种页面错误相对便宜,称为“软”页面错误,如果机器没有受到压力,并且必须取消另一个进程正在使用的页面的映射以获取RAM。您希望操作系统能够抓取一个页面并对其进行映射,开销以微秒为单位

因此,实际上,如果您做得正确,并且在分配数组时不尝试初始化整个数组,那么您的程序将承受数以万计的开销。每一个都足够小,不会危及实时响应保证。无论是早分配还是晚分配内存,都会发生这种情况,因此是否使用两阶段构造并不重要

如果您希望保证不会发生这种情况,或者希望能够在初始化整个阵列时抵御大量页面错误,那么您需要一种非常不同的方法,您需要对RAM分配进行页面锁定,以便操作系统无法取消页面映射。这总是需要修改操作系统设置,它通常不允许进程页锁定大量内存。当然,两个阶段的建设也即将开始

请记住,程序很少知道如何处理分配失败。它们的行为几乎类似于异步异常,随时可以在任何时间点攻击
 class VeryHeavy {

 private:

    HeavyClass1* p1;
    HeavyClass2* p2;
    HeavyClass3* p3;
    HeavyClass4* p4;
    HeavyClass5* p5;

    int* hugeArray [100000];

    //...//

};
vector<int> x;
struct Widget
{
    Widget(int x)
    {
        cout << "Widget(" << x << ")" << endl;
    }
    void foo()
    {
        cout << "Widget::foo()" << endl;
    }
};

int main()
{
    auto &&x = make_lazy<Widget>(11);
    cout << "after make_lazy" << endl;
    x->foo();
}
after make_lazy
Widget(11)
Widget::foo()
#include <boost/utility/in_place_factory.hpp>
#include <boost/optional.hpp>
#include <iostream>
#include <utility>

using namespace boost;
using namespace std;

template<typename T, typename Factory>
class Lazy
{
    mutable optional<T> x;
    Factory f;

    T *constructed() const
    {
        if(!x) x = f;
        return &*x;
    }
public:
    Lazy(Factory &&f) : f(f) {}

    T *operator->()
    {
        return constructed();
    }
    const T *operator->() const
    {
        return constructed();
    }
};

template<typename T, typename ...Args>
auto make_lazy(Args&&... args) -> Lazy<T, decltype(in_place(forward<Args>(args)...))>
{
    return {in_place(forward<Args>(args)...)};
}

/*****************************************************/

struct Widget
{
    Widget(int x)
    {
        cout << "Widget(" << x << ")" << endl;
    }
    void foo()
    {
        cout << "Widget::foo()" << endl;
    }
};

int main()
{
    auto &&x = make_lazy<Widget>(11);
    cout << "after make_lazy" << endl;
    x->foo();
}