Unable to change the value of the variable
I'm using a discrete event simulator called ns-2 that was built using Tcl and C++. I was trying to write some code in TCL:
set ns [new Simulator]
set state 0
$ns at 0.0 "puts \"At 0.0 value of state is: $state\""
$ns at 1.0 "changeVal"
$ns at 2.0 "puts \"At 2.0 values of state is: $state\""
proc changeVal {} {
global state
global ns
$ns at-now "set state [expr $state+1]"
puts "Changed value of state to $state"
}
$ns run
Here's the output:
At 0.0 value of state is: 0
Changed value of state to 0
At 2.0 values of state is: 0
The value of state does not seem to change. I am not sure if I am doing something wrong in using TCL. Anyone has an idea as to what might be going wrong here?
EDIT: Thanks for the help. Actually, ns-2 is something over which I do not have much control (unless I recompile the simulator itself). I tried out the su开发者_运维百科ggestions and here's the output:
for the code:
set ns [new Simulator]
set state 0
$ns at 0.0 "puts \"At 0.0 value of state is: $state\""
$ns at 1.0 "changeVal"
$ns at 9.0 "puts \"At 2.0 values of state is: $state\""
proc changeVal {} {
global ns
set ::state [expr {$::state+1}]
$ns at-now "puts \"At [$ns now] changed value of state to $::state\""
}
$ns run
the output is:
At 0.0 value of state is: 0
At 1 changed value of state to 1
At 2.0 values of state is: 0
And for the code:
set ns [new Simulator]
set state 0
$ns at 0.0 "puts \"At 0.0 value of state is: $state\""
$ns at 1.0 "changeVal"
$ns at 9.0 "puts \"At 2.0 values of state is: $state\""
proc changeVal {} {
global ns
set ::state [expr {$::state+1}]
$ns at 1.0 {puts "At 1.0 values of state is: $::state"}
}
$ns run
the output is:
At 0.0 value of state is: 0
At 1.0 values of state is: 1
At 2.0 values of state is: 0
Doesn't seem to work... Not sure if its a problem with ns2 or my code...
Edit: now understanding the state machine
First, the quoting syntax you're using is going to get you in trouble. You should generally build up Tcl commands using list, this ensures that Tcl will not expand what you don't want it to expand.
Your at-now
calls are substituting the state
variable when you make the call (i.e. when the value is unchanged and 0. What you want is:
$ns at-now 0.0 {puts "At 0.0 value of state is: $::state"}
$ns at-now 2.0 {puts "At 2.0 value of state is: $::state"}
It looks like your changeVal
is properly written (the first version had some of the same substitution problems), as well as the fact that you were passing in variable references that would be used locally, and therefore not setting the global state.
Solution to part of first version of question - Use global references, and quote both the [
and $
to prevent substitution at the point of the call:
$ns at-now "set ::state \[expr {\$::state + 1}\]"
or, using curly braces:
$ns at-now {set ::state [expr {$::state + 1}]}
The problem is you're substituting the value of your variables immediately, and not at the time the code is evaluated. You need to postpone the substitution. Thus, instead of:
$ns at 2.0 "puts \"At 2.0 values of state is: $state\""
Do this:
$ns at 2.0 {puts "At 2.0 values of state is: $state"}
It's good practice to put anything more complex than a simple call of a command without substitution in a procedure when doing a call like this. Much easier to make it work right.
[EDIT]
Also, the at-now
is still postponing doing its body until after the current at
returns.
I am not sure why this works but it works:
set ns [new Simulator]
set state 0
proc changeVal {} {
global ns
incr ::state
$ns at-now {puts "Local::At [$ns now] values of state is: $::state"}
}
$ns at 0.0 "puts \"Global::At 0.0 value of state is: $state\""
changeVal
$ns at 9.0 "puts \"Global::At 2.0 values of state is: $state\""
$ns run
Output:
Global::At 0.0 value of state is: 0
Local::At 0 values of state is: 1
Global::At 2.0 values of state is: 1
If anyone knows an explanation, that would be great.
精彩评论