How does ns3 solve cross reference issue

First part

  The use of Ptr object may cause cross reference in ns3. How ns3 destroy the pointer in cross reference situation.
 Code example, ns3_ptr_ref.cc

#include <iostream>
#include <string>
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
namespace ns3{
class BClass;
class AClass:public Application{
public:
    ~AClass(){
        std::cout<<"A dtor"<<std::endl;
    }
    void Attach(Ptr<BClass> b);
protected:
    void StartApplication() override {}
    void StopApplication() override {}
    virtual void DoDispose (void);
    virtual void DoInitialize (void){}
private:
    Ptr<BClass> b_;
};
class BClass:public Application{
public:
    ~BClass(){
        std::cout<<"B dtor"<<std::endl;
    }
    void Attach(Ptr<AClass> a);
protected:
    void StartApplication() override {}
    void StopApplication() override {}
    virtual void DoDispose (void);
    virtual void DoInitialize (void){}
private:
    Ptr<AClass> a_;
};
void AClass::DoDispose (void){
    b_=0;
    std::cout<<"A DoDispose "<<GetReferenceCount()<<" "<<GetNode()->GetReferenceCount()<<std::endl;
    Application::DoDispose();
}
void AClass::Attach(Ptr<BClass> b){
    b_=b;
}
void BClass::DoDispose (void){
    a_=0;
    std::cout<<"B DoDispose "<<GetReferenceCount()<<" "<<GetNode()->GetReferenceCount()<<std::endl;
    Application::DoDispose();
}
void BClass::Attach(Ptr<AClass> a){
    a_=a;
}
void cross_ref_test(){
    Ptr<AClass> a=CreateObject<AClass>();
    Ptr<BClass> b=CreateObject<BClass>();
    a->Attach(b);
    b->Attach(a);
}
void cross_ref_with_node(bool run=true){
    Ptr<AClass> a=CreateObject<AClass>();
    Ptr<BClass> b=CreateObject<BClass>();
    a->Attach(b);
    b->Attach(a);
    Ptr<Node> h1=CreateObject<Node>();;
    std::cout<<"node "<<h1->GetReferenceCount()<<std::endl;  
    h1->AddApplication(a);
    h1->AddApplication(b);
    std::cout<<"ref "<<a->GetReferenceCount()<<std::endl;
    if(run){
        Simulator::Run ();
        Simulator::Destroy();
    }
    std::cout<<"ref "<<a->GetReferenceCount()<<std::endl;
    std::cout<<"ref "<<b->GetReferenceCount()<<std::endl;
    std::cout<<"node "<<h1->GetReferenceCount()<<std::endl;  
}
void count_init_node_ref(bool run=true){
    Ptr<Node> h1=CreateObject<Node>();;
    std::cout<<"node "<<h1->GetReferenceCount()<<std::endl;
    if(run){
        Simulator::Run ();
        Simulator::Destroy();        
    }
    std::cout<<"node "<<h1->GetReferenceCount()<<std::endl;
}
}

using namespace ns3;
void print_usuage(){
    std::cout<<"plese input the right command: "<<std::endl;
    std::cout<<"./waf --run \"scratch/ns3_ptr_ref 0\""<<std::endl;
}
int main(int argc,const char *argv[]){
    LogComponentEnable("NodeList",LOG_LEVEL_ALL);
    LogComponentEnable("Node",LOG_LEVEL_ALL);
    if(2==argc){
        std::string command(argv[1]);
        if(0==command.compare("0")){
            cross_ref_test();
        }else{
            cross_ref_with_node();
        }
    }else{
        print_usuage();
    }
    return 0;
}

cross_ref_test

 Running the command: ./waf --run “scratch/ns3_ptr_ref 0”. The function cross_ref_test will be called.
 In cross_ref_test, a will refer to b (a->Attach(b)) and b will refer to a (b->Attach(a)).
  When program exits, both a and b will not be destoyed.

cross_ref_with_node

 Running the command: ./waf --run "scratch/ns3_ptr_ref 1. The function cross_ref_with_node will be called.
  a and b will be added in node object as application. The Dispose function in Node will be called when Simulator::Destroy() is called. Dispose will call DoDispose.

void  Node::DoDispose (){
  for (std::vector<Ptr<Application> >::iterator i = m_applications.begin ();
       i != m_applications.end (); i++)
    {
      Ptr<Application> application = *i;
      application->Dispose ();
      *i = 0;
    }
}

  application->Dispose () will call DoDispose in Application. In object a, the reference to b is removed.

void AClass::DoDispose (void){
    b_=0;
    std::cout<<"A DoDispose"<<std::endl;
}

  Both a and b will be destroyed.

How NodeListPriv::DoDispose is triggered?

Ptr<NodeListPriv> * NodeListPriv::DoGet (void){
  static Ptr<NodeListPriv> ptr = 0;
  if (ptr == 0)
    {
      ptr = CreateObject<NodeListPriv> ();
      Config::RegisterRootNamespaceObject (ptr);
      Simulator::ScheduleDestroy (&NodeListPriv::Delete);
    }
  return &ptr;
}
void NodeListPriv::Delete (void){
  NS_LOG_FUNCTION_NOARGS ();
  Config::UnregisterRootNamespaceObject (Get ());
  (*DoGet ()) = 0;
}

  Before NodeListPriv is destroyed in Delete, the Dispose function in NodeListPriv will be called first.

void
NodeListPriv::DoDispose (void)
{
  NS_LOG_FUNCTION (this);
  for (std::vector<Ptr<Node> >::iterator i = m_nodes.begin ();
       i != m_nodes.end (); i++)
    {
      Ptr<Node> node = *i;
      node->Dispose ();
      *i = 0;
    }
  m_nodes.erase (m_nodes.begin (), m_nodes.end ());
  Object::DoDispose ();
}

class Object : public SimpleRefCount<Object, ObjectBase, ObjectDeleter>

void ObjectDeleter::Delete (Object *object){
  object->DoDelete ();
}

Second part

 During test, I found the Node object can be destroyed only after Simulator::Run () is called. After a node is created, its reference is 3. If run=false, h1 will not be destroyed.

void count_init_node_ref(bool run=true){
    Ptr<Node> h1=CreateObject<Node>();
    std::cout<<"node "<<h1->GetReferenceCount()<<std::endl;
    if(run){
        Simulator::Run ();
        Simulator::Destroy();        
    }
    std::cout<<"node "<<h1->GetReferenceCount()<<std::endl;
}

 The number 3 is analyzed here:

Node::Node()
  : m_id (0),
    m_sid (0)
{
  NS_LOG_FUNCTION (this);
  Construct ();
}
void Node::Construct (void){
  NS_LOG_FUNCTION (this);
  m_id = NodeList::Add (this);
}
uint32_t NodeList::Add (Ptr<Node> node){
  NS_LOG_FUNCTION (node);
  return NodeListPriv::Get ()->Add (node);
}
uint32_t NodeListPriv::Add (Ptr<Node> node) {
  NS_LOG_FUNCTION (this << node);
  uint32_t index = m_nodes.size ();
  m_nodes.push_back (node);
  Simulator::ScheduleWithContext (index, TimeStep (0), &Node::Initialize, node);
  return index;
}

When count_init_node_ref(false), the events in simulator will not traggier. The node object here Simulator::ScheduleWithContext (index, TimeStep (0), &Node::Initialize, node) will not derefered.

Reference:

[1] HOWTO resolve circular references in ns-3 memory disposal
[2] NS3 Node聚合对象说明

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值