Ran*_*dan 5 c++ constructor class real-time
我正在开发一个实时系统,我正在讨论类的设计.
具体来说,我无法决定是否使用两阶段构造来构建"重型"类.
一方面,调用"重"类的构造函数可能是运行时的主要瓶颈,它使我免于创建类和分配用户可能不会使用的功能的内存.
另一方面,考虑到我们尝试访问一种能力时的情况,两阶段构造可以在执行期间产生意外,但我们不能因为它没有初始化,突然我们需要在使用之前完全构建它.
我的倾向是采用两阶段施工方法.我喜欢听到的是实时系统中两阶段构建的优点.如果有更好的方法来解决这个问题.
这里是一个重类的代码示例(我的类肯定不会那样,但它证明了我的想法):
class VeryHeavy {
private:
HeavyClass1* p1;
HeavyClass2* p2;
HeavyClass3* p3;
HeavyClass4* p4;
HeavyClass5* p5;
int* hugeArray [100000];
//...//
};
Run Code Online (Sandbox Code Playgroud)
Han*_*ant 21

这是AGC,Apollo Guidance Computer,用于Apollo命令模块和月球模块.着名的几乎导致阿波罗11号着陆被擦洗.在下降到月球表面的中间,这台计算机因实时错误而崩溃.几次.产生系统错误1201(执行溢出 - 没有空白区域)和系统错误1202(执行溢出 - 没有核心集).阿姆斯特朗和奥尔德林只看到了数字,你在照片右边看到的UI设备太原始了,无法显示字符串.指导控制员Steve Bales知道数字意味着什么(他们在训练时从未见过错误)并且知道系统可以从中恢复.无论如何,通过给予GO来挽救着陆,他获得了总统自由勋章.
这可能是你的问题所要求的,尽管我们可以非常肯定你并没有试图降落火箭."实时"这个术语曾经在软件工程中得到了很好的定义,但却受到了金融业的困扰.在Apollo 11中,它意味着一个系统对外部事件的最大响应时间有一个非常严格的上限.火箭队需要一个这样的系统,有时候调整喷嘴时不能太晚,迟到一次会产生十亿美元的火球.金融业劫持它意味着一个任意快速的系统,迟到有时不会使机器蒸发,尽管它使交易损失的可能性更大.他们可能也认为这也是灾难:)
您使用的内存分配器很重要,也没有在问题中定义.我会假设您的程序在需求分页的虚拟内存操作系统上运行.不完全是实时系统的理想环境,但通常情况下,真正的实时操作系统并不是很好.
两阶段构造是一种用于处理初始化失败的技术,构造函数中抛出的异常很难处理,析构函数不会运行,如果在构造函数中分配而导致资源泄漏,而不会使构造函数足够智能处理一个事故.另一种方法是稍后在成员函数内执行,根据需要懒惰地分配.
所以你担心的是,懒惰分配会妨碍系统的响应能力.产生系统错误1201.
事实上,这并不是像Linux或Windows这样的需求分页虚拟内存操作系统的主要问题.这些操作系统上的内存分配器速度很快,只分配虚拟内存.哪个不花钱,它是虚拟的.当你真正开始使用分配的内存时,真正的成本会在以后出现.需求分页的"需求"发挥作用.寻址数组元素会产生页面错误,迫使操作系统将寻址的虚拟内存页映射到RAM中.这样的页面错误相对便宜,称为"软"页面错误,如果机器没有其他压力并且必须取消映射另一个进程正在使用的页面来获取RAM.您希望操作系统能够抓取页面并映射它,开销以微秒为单位.
所以实际上,如果你做得对,并且在分配它时不尝试初始化整个数组,那么你的程序将受到成千上万的小开销.每一个小到足以不危及实时响应保证.无论您是提前还是延迟分配内存,都会发生这种情况,因此无论您使用两阶段构造都无关紧要.
如果你想保证不会发生这种情况,或者想要适应初始化整个阵列时遇到的页面错误风暴,那么你需要一个非常不同的方法,你需要页面锁定RAM分配使操作系统无法取消映射页面.这总是需要修改操作系统设置,它通常不允许进程对大量内存进行页面锁定.当然,两相结构也是出门的.
请记住,程序很少知道如何处理分配失败.它们的行为几乎就像异步异常一样,随时可以在程序的任何时间点触发.特别难以与实时要求协调一致,因为内存耗尽而对实时事件没有响应的系统当然不会比最晚的系统更好.这仍然是一个火球;)因此,本身应该已经足够理由不打扰两阶段构造,只需在程序初始化时分配内存,然后再开始承诺实时响应.它使编码程序的很多简单的,失败的几率要低得多.
对于任何具有实时特性的软件来说,一个非常困难的要求是它不必与其他进程争夺获取操作系统资源.预计将整个机器专用于一个过程,您不再局限于36864字的绳索内存和2048字的RAM,就像AGC一样.如今,硬件便宜且充足,可提供这样的保证.