释放(deletion):Delete操作将释放解释对象和相应的编译对象,可以说是new操作的逆过程。使用的语句是:delete scheduler_
(2)变量的绑定(bindding)
一般而言,编译代码只能访问编译变量,解释代码只能访问解释变量。因此,每一实体都由两个变量来表示,需要系统进行双向绑定。在这里,绑定的意思是,相应的两个变量时刻保持一致,当一方发生改变,另一方也要发生同样的变化。
变量的绑定有显式、隐式两种。隐式变量绑定是在初始化一个对象时,由编译对象的构造函数建立的。之后,解释对象便将它视为实例变量。
(4)变量的跟踪(Trace)
跟踪变量(traced variable)由C++ 或Tcl生成、修改。它又分为对解释变量的跟踪和对编译变量的跟踪。
对解释变量的跟踪:若想用Tcl代码对变量进行跟踪,则此变量必须是Tcl代码可见的,比如:已绑定的C++/Tcl变量,或是纯的Tcl变量。根据被跟踪变量的拥有者不同,可分两种情况:
1) 拥有者为自己,例如\$tcp跟踪自己的变量cwnd_:
\$tcp trace cwnd_
2) 拥有者为别人,例如,有一普通跟踪者\$tracer跟踪\$tcp的变量ssthresh_:
set tracer [new Trace/Var]
\$tcp trace ssthresh_ \$tracer
对编译变量的跟踪:被跟踪的变量必须属于TraceVar类的派生类。虚基类TracedVar的部分定义如下:
class TracedVar {
virtual char* value(char* buf) = 0;
protected:
TracedVar(const char* name);
const char* name_; // name of the variable
TclObject* owner_; // the object that owns this variable
TclObject* tracer_; // callback when the variable is changed
…… …… ……
};
TclCL库对int型和double型变量分别定义了两类TracedVar:TracedInt和TracedDouble。它们重载了所有的操作符。当变量的值发生改变时,用assign方法给变量赋新值,并调用tracer 。TracedInt和 TracedDouble还实现了value ,将变量的值转为串
(5)命令方法的定义和调用
ns为每一的TclObject 建立一个实例过程 cmd{},cmd{}自动调用编译对象的command()函数。用户可以通过两种方法调用cmd{} :显示调用,指定想要的操作为第一参数;或是隐式调用,就好像存在与想要的操作同名的实例过程。绝大多数的脚本使用后一种形式。我们先介绍这种方式,简单起见,以srmObject对象为例子:
SRM中有关距离的计算是由编译对象完成的,而由解释对象使用。调用如下:
$srmObject distance? (agentAddress)
若不存在名为 distance? 实例过程,解释器将调用实例过程unknown{},(在基类TclObject中定义),然后unknown{}调用:
$srmObject cmd distance? _ agentAddress
通过编译对象的command()过程来执行操作。
当然用户可以显式调用操作,好处是可以重载,对应的Otcl代码和C++代码如下:
Agent/SRM/Adaptive instproc distance? addr {
$self instvar distanceCache_
if ![info exists distanceCache_($addr)] {
set distanceCache_($addr) [$self cmd distance? $addr]
}
set distanceCache_($addr)
}
int ASRMAgent::command(int argc, const char*const*argv) {
Tcl& tcl = Tcl::instance();
if (argc == 3) {
if (strcmp(argv[1], "distance?") == 0) {
int sender = atoi(argv[2]);
SRMinfo* sp = get_state(sender);
tcl.tesultf("%f", sp->distance_);
return TCL_OK;
}
}
return (SRMAgent::command(argc, argv));
}
int ASRMAgent::command()函数有两个参数:
第一个参数(argc)指出命令行中的参数个数。
第二个为命令行参数向量,解释如下:argv[0]——方法名“cmd”;argv[1]——指定想要的操作;若用户还指定了其余参数,在argv[2...(argc - 1)]中。
参数是以字串形式给出的,应该先转化成相应的数据类型。
若操作匹配成功,返回操作结果,tcl.tesultf("%f", sp->distance_);
command() 必须返回TCL_OK或TCL_ERROR ;
如果操作不匹配,调用父类的command()函数,返回相应结果,若一直到最底层的基类都不匹配,返回错误信号。这样做,允许子类继承其父类的命令。
在多继承情况下,可以有两种选择:1、指定继承一个父类的command();2、按某种顺序访问几个父类的command(),一找到匹配的,就不再试下一个,如果都不行,返回一个错误信号。
(3) TclClass类:
类TclClass是一个纯虚类,从它派生的子类需实现两个成员函数:其一是构造函数,构造解释类层次来镜像编译类层次;其二是生成函数,生成与之相对应的TclObjects对象。在~ns/tclcl.h中可以找到定义。
用个简单的例子说明一下整个的流程。比如,脚本中有这样一行:
set o [new B/A ]
则:对象o的解释构造函数在ns第一次启动时执行
Ø 此构造函数以解释类的名字B/A调用ABClass的构造函数
Ø 然后,ABClass构造函数将调用其父类TclClass的构造函数
Ø TclClass构造函数存储类的名字,并将对象插入TclClass对象链中
Ø 在simulator的初始化过程中,Tcl_AppInit(void)调用TclClass::bind(void)。
bind()调用以解释类的名为参数register{},
register{}建立类层次,生成需要而还没有的类。
Ø 最后,bind()为新类定义实例过程create-shadow和delete-shadow,生成并返回对象o。
其流程示意图如图2.4所示:若图片无法显示请联系QQ752018766
图2.4
类TclCommond的作用就在为解释器提供全局命令。
由TclCommand在C++中的定义(~ns/tclcl.h),可以看出,它也是个纯虚类,需要派生类实现实现两个成员函数:构造函数和command()。
比如,如果用户希望敲入命令:% say I am ns user返回:>hellow, I am ns user。
则我们可以从TclCommand派生出子类MyCommand,它的构造函数用“say”为参数,代码为:
class say_hello : public TclCommand {
public:say_hello();
int command(int argc, const char*const* argv);};
class MyClass:TclCommand(”say”){}
然后,再实现MyCommand::command()即可。
注意:TclCommand定义里有一个dispatch_cmd()的静态函数,实现了从“say”
上一页 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] ... 下一页 >>