代码之家  ›  专栏  ›  技术社区  ›  e.jahandar

C++中循环引用变量依赖性的求解

  •  -1
  • e.jahandar  · 技术社区  · 8 年前

    假设我有下面的代码,用C++来构造数据流体系结构

    class DataflowClass {
        public:
            DataflowClass(int & _a, int & b) : a(_a), b(b){}
    
            inline void calculate(){
                c = a + b;
                d = a - 2*b;
            }
    
            inline int & getC() { return c; }
            inline int & getD() { return d; }
    
        private:
            int c = 1;
            int d = 2;
            int & a;
            int & b;
    };
    
    void TestReferenceVariableDataflow(int count){
    
        int a;
        int b;
    
        DataflowClass c1(a, b);
        DataflowClass c2(c1.getC(), c1.getD());
        DataflowClass c3(c2.getC(), c2.getD());
    
        for(int i=0;i<count;i++){
            a = c3.getC();
            b = c3.getD();
            c1.calculate();
            c2.calculate();
            c3.calculate();
        }
    }
    

    DataFlowClass是具有两个输入和两个输出的数据流块的主要构建。dataflowClass的构造函数接受两个引用变量作为输入,并具有两个getter函数,该函数返回对其两个输出成员的引用。 可以看到,在testReferenceVariableDataFlow函数i构造了3个dataFlowClass实例,c1实例是通过引用testReferenceVariableDataFlow函数中定义的两个局部变量构造的,c2是通过从c1.getc()和c2.getc()混合的两个引用构造的,反之亦然。

    在每次迭代中,3个类的计算方法称为定义顺序,这将导致3个类中的数据流计算。

    真正的问题是循环依赖,如您所见,c1是用testReferenceVariableDataFlow函数中定义的两个变量的引用构造的,在每次迭代结束时,我必须将c3.getc()和c3.getd()中的值复制到这些变量中。

    由于dataflowClass在其构造函数中接受引用变量,因此我无法将c3的输出变量直接连接到c1,因为c3实例在c1的构造时不可用,因此我必须定义两个额外的变量来将每次迭代中的值从最后一个复制到第一个。

    如您所知,具有引用成员的类应该在构造时初始化引用,这个问题导致了循环依赖性问题。

    这个循环依赖问题有什么解决方案吗?

    编辑 这种设计背后有一些简单的原因,

    1 -首先,这是设计只使用C++泛型语法,而不是任何其他类型的库,甚至STD::*,仅仅因为性能,认为有几十个这些块,并且所有的串行连接, 避免使用库的另一个原因是,此代码是实时软件的一部分,其行为比库更容易预测

    2-数据流类的实例永远不会被破坏,我们不能有悬空指针

    3-在时间关键和实时软件中,由于不可预测性,动态内存管理以某种方式被禁止,而且这种设计确实可以与所有静态内存分配一起使用。

    4-指针的使用被认为不是一个好的解决方案,因为指针的静态编译时断言无法实现,因此编译时连接可防止未连接的输入网络 指针也可能得到空值或类似的值。

    5-这种设计不需要每个变量的变化信号,因为所有的计算方法都将被串行调用,也可以用父类自动调用。

    6-块的输入可能来自不同的块(与以前的块不同),提供的示例只是一个简单的例子,块之间均匀连接。

    7 -简单的设计将是Simulink块的C++实现,块的输出连接到其他块的输入,并且它们将以时间增量来计算它们的输出。

    4 回复  |  直到 7 年前
        1
  •  2
  •   Jarod42    8 年前

    class DataflowClass {
    public:
        DataflowClass() = default;
    
        DataflowClass(int& pa, int& pb) : a(&pa), b(&pb){}
        void linkTo(int& pa, int& pb) { a = &pa; b = &pb; }
    
        void calculate(){
            assert(a != nullptr && b != nullptr);
            c = *a + *b;
            d = *a - 2 * *b;
        }
    
        int & getC() { return c; }
        int & getD() { return d; }
    
    private:
        int c = 1;
        int d = 2;
        const int* a = nullptr;
        const int* b = nullptr;
    
    };
    
    void TestReferenceVariableDataflow(int count)
    {
        DataflowClass c1;
        DataflowClass c2(c1.getC(), c1.getD());
        DataflowClass c3(c2.getC(), c2.getD());
        c1.linkTo(c3.getC(), c3.getD());
    
        for(int i=0;i<count;i++){
            c1.calculate();
            c2.calculate();
            c3.calculate();
        }
    }
    

    std::pair<int, int> calculate(int a, int b) { return { a + b, a - 2 * b} ; }
    
    void TestReferenceVariableDataflow(int count)
    {
        int a = 1;
        int b = 2;
    
        for(int i=0;i<count;i++){
            std::tie(a, b)  = calculate(a, b);
            std::tie(a, b)  = calculate(a, b);
            std::tie(a, b)  = calculate(a, b);
        }
    }
    
        2
  •  1
  •   hoffmale    8 年前

    class DataFlowClass {
        const int& a;
        const int& b;
        int& c;
        int& d;
    
    public:
        DataFlowClass(const int& a, const int& b, int& c, int& d) : a{a}, b{b}, c{c}, d{d} {
            c = 1;
            d = 2;
        }
    
        void calculate() {
            c = a + b;
            d = a - 2*b;
        }
    };
    
    void TestReferenceVariableDataflow(int count){
        int storage[6]; // could use 6 int variables instead
    
        DataflowClass c1(storage[0], storage[1], storage[2], storage[3]);
        DataflowClass c2(storage[2], storage[3], storage[4], storage[5]);
        DataflowClass c3(storage[4], storage[5], storage[0], storage[1]);
    
        for(int i=0;i<count;i++){
            c1.calculate();
            c2.calculate();
            c3.calculate();
        }
    }
    

    Jarod42's answer

        3
  •  0
  •   Slava    8 年前

    class DataflowClass {
        public:
            void calculate(const DataflowClass &from ){
                c = from.getC() + from.getD();
                d = from.getC() - 2*from.getD();
            }
    
            int getC() const { return c; }
            int getD() const { return d; }
    
        private:
            int c = 1;
            int d = 2;
    };
    
    void TestReferenceVariableDataflow(int count){
        std::array<DataflowClass,3> c;
    
        for(int i=0;i<count;i++){
            for( size_t i = 0; i < c.size(); ++i ) {
                auto prev = ( i == 0 ? c.size() : i ) - 1;
                c[i].calculate( c[prev] ); 
            }
        }
    }
    

        4
  •  0
  •   e.jahandar    7 年前

    class DataflowClass {
        public:
            DataflowClass(){}
    
            inline void setInputs(int & _a, int & _b){
                this->a = _a ;
                this->b = _b;
            }
    
            inline void calculate(){
                c = a + b;
                d = a - 2*b;
            }
    
            inline int & getC() { return c; }
            inline int & getD() { return d; }
    
        private:
            int c = 1;
            int d = 2;
            int a_initial = 0;
            int b_initial = 0;
            std::reference_wrapper<int> a = a_initial;
            std::reference_wrapper<int> b = b_initial;
    };
    
    void TestReferenceVariableDataflow(int count){
    
        DataflowClass c1, c2, c3;
        c2.setInputs(c1.getC(), c1.getD());
        c3.setInputs(c2.getC(), c2.getD());
        c1.setInputs(c3.getC(), c3.getD());
    
        for(int i=0;i<count;i++){
            c1.calculate();
            c2.calculate();
            c3.calculate();
        }
    }