Tictoc3例子

在tictoc3中,实现了让 tic 和 toc 这两个简单模块之间传递消息,传递十次后结束仿真。
首先来介绍一下程序中用到的两个函数:
1.omnetpp中获取模块名称的函数

 virtual const char *getName() const override  {
     return name ? name : "";
 }

2.定义及初始化消息的函数

cMessage *msg = new cMessage("tictocMsg");

接着来看一下网络描述文件 tictoc3.ned, 这个文件中定义了所仿真的网络是什么样子的。

//
// This file is part of an OMNeT++/OMNEST simulation example.
//
// Copyright (C) 2003-2015 Andras Varga
//
// This file is distributed WITHOUT ANY WARRANTY. See the file
// `license' for details on this and other legal matters.
//
simple Txc3
{
    parameters:
        @display("i=block/routing");
    gates:
        input in;
        output out;
}

//
// Same as Tictoc2.
//
network Tictoc3
{
    submodules:
        tic: Txc3 {
            parameters:
                @display("i=,cyan");
        }
        toc: Txc3 {
            parameters:
                @display("i=,gold");
        }
    connections:
        tic.out --> {  delay = 100ms; } --> toc.in;
        tic.in <-- {  delay = 100ms; } <-- toc.out;
}

可以看到,在上述的代码段中,定义了一个简单模块的结构Txc3,里面包含了一个输入门in 和输出门 out 。随后在 Tictoc3 这个网络中,创建了Txc3 的两个实例 tic 和 toc ,并创建了它们之间的连接,即两条时延为100ms 的信道,使两模块可以互相通信。
定义好了ned文件后需要把Tictoc3这个网络配置到初始化文件omnetpp.ini当中,指明仿真所使用的是哪个网络。

[Config Tictoc3]
network = Tictoc3

最后我们来看一下tic 和 toc 之间的消息传递是怎么实现的,这就要前往表示行为的.cpp文件了。

//
// This file is part of an OMNeT++/OMNEST simulation example.
//
// Copyright (C) 2003-2015 Andras Varga
//
// This file is distributed WITHOUT ANY WARRANTY. See the file
// `license' for details on this and other legal matters.
//

#include <stdio.h>
#include <string.h>
#include <omnetpp.h>

using namespace omnetpp;

/**
 * In this class we add a counter, and delete the message after ten exchanges.
 */
class Txc3 : public cSimpleModule
{
  private:
    int counter;  // Note the counter here

  protected:
    virtual void initialize() override;      
    virtual void handleMessage(cMessage *msg) override;  
};

Define_Module(Txc3);   //识别Txc3这个类

void Txc3::initialize()
{
    // Initialize counter to ten. We'll decrement it every time and delete
    // the message when it reaches zero.
    counter = 10;

    // The WATCH() statement below will let you examine the variable under
    // Tkenv. After doing a few steps in the simulation, double-click either
    // `tic' or `toc', select the Contents tab in the dialog that pops up,
    // and you'll find "counter" in the list.
    WATCH(counter);      //表示在仿真中可以查看当前这个变量的状态

    if (strcmp("tic", getName()) == 0) {
        EV << "Sending initial message\n";            //仿真界面输出信息
        cMessage *msg = new cMessage("tictocMsg");
        send(msg, "out");          //
    }
}

void Txc3::handleMessage(cMessage *msg)
{
    // Increment counter and check value.
    counter--;
    if (counter == 0) {
        // If counter is zero, delete message. If you run the model, you'll
        // find that the simulation will stop at this point with the message
        // "no more events".
        EV << getName() << "'s counter reached zero, deleting message\n";
        delete msg;
    }
    else {
        EV << getName() << "'s counter is " << counter << ", sending back message\n";
        send(msg, "out");
    }
}

我们来分析一下这个程序。首先在Txc3这个类中,定义了一个成员变量counter,这个是用来标记模块发送了多少的消息的;接着声明了两个方法:initialize() 和 handleMessage() , 其中 initialize()指明初始化的时候要做出什么样的操作,handleMessage(cMessage *msg)指明接收到消息的时候要做出什么样的处理。接下来分别解读一下这两个函数。
initialize()

void Txc3::initialize()
{
    // Initialize counter to ten. We'll decrement it every time and delete
    // the message when it reaches zero.
    counter = 10;

    // The WATCH() statement below will let you examine the variable under
    // Tkenv. After doing a few steps in the simulation, double-click either
    // `tic' or `toc', select the Contents tab in the dialog that pops up,
    // and you'll find "counter" in the list.
    WATCH(counter);      //表示

    if (strcmp("tic", getName()) == 0) {
        EV << "Sending initial message\n";          
        cMessage *msg = new cMessage("tictocMsg");
        send(msg, "out");         
    }
}

在这个函数中,首先初始化了Txc3类中的成员变量值为10; WATCH(counter)这条语句的作用是为了能够在仿真中可以查看当前这个变量的状态;接下来是判断当前模块是否为 tic,如果是的话就在仿真界面输出信息"Sending initial message",并创建一个新消息msg从tic模块的 out 门发送出去。这样就实现了让 tic 模块先传递消息给toc。然后我们来看一下初始化之后的样子,如下图所示:
image.png
从仿真日志里可以看出,在还没有开始tictoc3的仿真时,就完成了初始化网络的操作,即构建好tictoc3这个网络,并初始化 tic 和 toc 两模块之间的信道;而且初始化的时候会调用 initialize() 初始化两个模块tic 和 toc,对于toc模块的初始化就是创建出了这个模块,而对于 tic 模块则是在创建后向 toc 模块发送了一个cMessage消息,但是这个时候 toc 还没有收到,因为handleMessage(cMessage *msg)函数是在开始仿真的时候才会执行的。从下图中就可以看出,此时这个代表消息的红点还没有到达 toc 模块。
image.png
*handleMessage(cMessage msg)

void Txc3::handleMessage(cMessage *msg)
{
    // Increment counter and check value.
    counter--;
    if (counter == 0) {
        // If counter is zero, delete message. If you run the model, you'll
        // find that the simulation will stop at this point with the message
        // "no more events".
        EV << getName() << "'s counter reached zero, deleting message\n";
        delete msg;
    }
    else {
        EV << getName() << "'s counter is " << counter << ", sending back message\n";
        send(msg, "out");
    }
}

可以看到在这个函数中就没有区分是 tic 模块还是toc 模块了,那也就是说tic 和 toc 在收到对方发来的消息时所作的处理是一样的。首先会把自己的计时器counter减一,表示已经收到了一次消息了,接着判断counter的值有没有减到零,是的话就表示已经收到十次来自对方的消息了,这个时候就删除掉该消息,然后不再发送;如果没有减为零,先在仿真界面输出一下此时的counter值,接着把收到的消息 tictocMsg 从自己的 out 门发送出去。
接下来点击运行仿真,跟踪整体的仿真事件:
image.png
可以看到,在没有了事件时,仿真就会结束。
下面详细看一下仿真日志的输出:
image.png
当toc模块第十次收到tictocMsg这个消息时,它的counter值就递减到零了,所以Event19 就是最后一个事件。由于是 tic 先发送消息给 toc 的,所以在传递的过程中,一定是 toc 模块先收到最后一个消息。
此外,前面提到WATCH(counter)语句是保证在仿真中可以查看counter的状态,所以在仿真中只需双击 tic 或 toc 模块就可以看到对应模块的 counter 值了。如下图所示:
image.png
可见,此时toc模块的 counter 值为8,也就是说toc已经收到了两次来自tic的消息了。
以上就是对 tictoc 的第三个例子的解读,若有更加通透的见解欢迎评论区留言分享。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/451756.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python 一步一步教你用pyglet制作汉诺塔游戏(终篇)

目录 汉诺塔游戏 完整游戏 后期展望 汉诺塔游戏 汉诺塔&#xff08;Tower of Hanoi&#xff09;&#xff0c;是一个源于印度古老传说的益智玩具。这个传说讲述了大梵天创造世界的时候&#xff0c;他做了三根金刚石柱子&#xff0c;并在其中一根柱子上从下往上按照大小顺序摞…

js【详解】Promise

为什么需要使用 Promise &#xff1f; 传统回调函数的代码层层嵌套&#xff0c;形成回调地狱&#xff0c;难以阅读和维护&#xff0c;为了解决回调地狱的问题&#xff0c;诞生了 Promise 什么是 Promise &#xff1f; Promise 是一种异步编程的解决方案&#xff0c;本身是一个构…

套接字的地址结构,IP地址转换函数,网络编程的接口

目录 一、套接字的地址结构 1.1 通用socket地址结构 1.2 专用socket地址结构 1.2.1 tcp协议族 1.2.3 IP协议族 二、IP地址转换函数 三、网络编程接口 3.1 socket() 3.2 bind() 3.3 listen() 3.4 accept() 3.5 connect() 3.6 close() 3.7 recv()、send() 3.8 recv…

手写简易操作系统(五)--获得物理内存容量

前情提要 上一章中我们进入了保护模式&#xff0c;并且跳转到了32位模式下执行。这一章较为简单&#xff0c;我们来获取物理内存的实际容量。 一、获得内存容量的方式 在Linux中有多种方法获取内存容量&#xff0c;如果一种方法失败&#xff0c;就会试用其他方法。其本质上是…

考研数学|汤家凤《1800》vs 张宇《1000》,怎么选?

汤家凤的1800题和张宇的1000题都是备考数学考研的热门选择&#xff0c;但究竟哪个更适合备考呢&#xff1f;下面分享一些见解。 首先&#xff0c;让我们来看看传统习题册存在的一些问题。虽然传统习题册通常会覆盖考试的各个知识点和题型&#xff0c;但其中一些问题在于它们可…

JDBC连接MysqL

import java.sql.*;public class Demo {public static void main(String[] args) throws ClassNotFoundException, SQLException {//1.注册驱动&#xff0c;加载驱动&#xff1b;Class.forName("com.mysql.jdbc.Driver");//2.获得连接,返回connection类型的对象&…

汤唯短发造型:保留经典和适合自己的风格,也许才是最重要的

汤唯短发造型&#xff1a;保留经典和适合自己的风格&#xff0c;也许才是最重要的 汤唯短发造型登上Vogue四月刊封面&#xff0c;引发网友热议。#李秘书讲写作#说说是怎么回事&#xff1f; 这次Vogue四月刊的封面大片&#xff0c;汤唯以一头短发亮相&#xff0c;身穿五颜六色的…

钉钉平台“智”领宠物界,开启萌宠智能新时代!

在当前数字化转型的浪潮中&#xff0c;钉钉用便捷的数字化解决方案推动了宠物业界的智能升级。一家宠物用品公司采用无雀科技数字化管理系统&#xff0c;与钉钉平台结合&#xff0c;解决了小型企业普遍存在的财务管理不清晰、业务流程不规范、客户信息核对繁琐等痛点问题。 针对…

一周学会Django5 Python Web开发-Django5内置模板引擎-模板继承

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计34条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

Linux中文件的权限

我们首先需要明白&#xff0c;权限 用户角色 文件的权限属性 一、拥有者、所属组和other&#xff08;用户角色&#xff09; 以文件file1为例 第一个箭头所指处即是文件的拥有者&#xff0c;拥有者为zz 第二个箭头所指处即使文件的所属组&#xff0c;所属组为zz 除去拥有者…

嵌入式系统工程师错题总结

笔者来介绍一下嵌入式系统工程师考试的一些易错题目 题目介绍  流水线指令计算公式&#xff1a;一条指令总时间max&#xff08;单个指令执行时间&#xff09;*&#xff08;指令数-1&#xff09;  平均故障间隔时间  ICMP协议&#xff1a;传送通信问题相关的消息。 …

电脑打开应用慢

电脑打开什么应用都很慢 我的电脑是i73060&#xff0c;但是打开应用很慢 解决办法&#xff1a; 在注册表[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CI\Policy]将"VerifiedAndReputablePolicyState"的值设置为0&#xff0c;如果没有这一项&#xff0c;就…

SPI、Spring SPI、SpringFactoriesLoader

一、SPI技术 SPI全名Service Provider interface&#xff0c;翻译过来就是“服务提供接口”&#xff0c;再说简单就是提供某一个服务的接口&#xff0c; 提供给服务开发者或者服务生产商来进行实现。 Java SPI 是JDK内置的一种动态加载扩展点的实现。 这个机制在一般的业务代…

【数据集】2023自动驾驶开源数据集-学习笔记

文章目录 1. 自动驾驶有哪些公开数据集2. 预测相关的数据集有哪些 1. 自动驾驶有哪些公开数据集 waymo open dataset 适应任务: 域适应&#xff0c;2D追踪&#xff0c;2D检测&#xff0c;3D追踪&#xff0c;3D检测&#xff0c;实时2D检测&#xff0c;实时3D检测&#xff0c;交互…

深入解析Java内存模型

一、背景 并发编程本质问题是&#xff1a;CPU、内存以及IO三者之间的速度差异。CPU速度快于内存、内存访问速度又远远快于IO&#xff0c;根据木桶理论&#xff0c;程序性能取决于最慢的操作&#xff0c;即IO操作。这样会出现CPU和内存交互时&#xff0c;CPU性能无法被充分利用…

使用命令行查看同一局域网内所有ip地址

由于学科实践课程提供的局域网IP扫描软件在本机上运行时&#xff0c;无法扫描出树莓派&#xff08;可能和防火墙设置有关&#xff1f;&#xff09;&#xff0c;所以记录一种通过命令行查看同一局域网下设备IP地址的方法&#xff0c;以手机热点下查找树莓派IP为例。 Step1&#…

Hive面经

hive原理 Hive 内部表和外部表的区别Hive 有索引吗运维如何对 Hive 进行调度ORC、Parquet 等列式存储的优点数据建模用的哪些模型&#xff1f;1. 星型模型2. 雪花模型3. 星座模型 为什么要对数据仓库分层&#xff1f;使用过 Hive 解析 JSON 串吗sort by 和 order by 的区别数据…

读书笔记之《机器与人》:AI如何重构工作方式和流程?

《机器与人: 埃森哲论新人工智能》作者是【美】保罗•多尔蒂和詹姆斯•威尔逊 &#xff0c;原作名: Human Machine: Reimagining Work in the Age of AI&#xff0c;2018年出版。 保罗•多尔蒂&#xff08;PAUL DAUGHERTYH&#xff09;&#xff1a;埃森哲首席技术官和创新官、…

策略迭代和价值迭代

策略迭代价值迭代 策略迭代&#xff08;Policy Iteration&#xff09;基本步骤例子&#xff1a;公主的营救 价值迭代&#xff08;Value Iteration&#xff09;基本步骤例子&#xff1a;公主的营救 策略迭代与价值迭代的区别实现方式目标收敛速度与其他技术的交互 策略迭代&…

浅谈Redis 的 保护模式(protected-mode)

今天在一台服务器上面部署了redis,发现始终无法用工具远程连接,项目里面是正常的,就是工具不行,防火墙也关闭了.折腾了一会才突然想起来,是不是触发了保护模式. 什么时候触发保护模式protected-mode: 同时满足以下两个: 1.bind未指定ip 2.未配置密码 解决方案: 编辑redis…