Add commands in a loop procedure while it is running

Viewed 55

My goal is to add commands to a loop that is already running , I know how to do it with global variables like this :

proc myLoop {} {
   global cmd1 cmd2 cmd3
   if {$cmd1} {
       # do something...
   }
   if {$cmd2} {
       # do something...
   }
   # ...
   
   after 1000 myLoop
}

set cmd1 0 ; set cmd2 1
myLoop

I’d like to do this on the fly : addCmdInLoop [list myCmd $arg1 $arg2] . I had thought to rename my myLoop every time and replace it but I don’t know if this is possible or efficient.

2 Answers

You can put your commands in a list and process that list every time. To add a command, just append it to the list.

proc myLoop {} {
    global cmdlist
    foreach cmd $cmdlist {
        # Execute the command in the global scope
        uplevel #0 $cmd
    }
    after 1000 myLoop
}
set cmdlist [list $cmd1 $cmd2]
# Start the loop
myLoop
# Add a command
lappend cmdlist [list myCmd $arg1 $arg2]

You can also get fancy with a coroutine to avoid using a global variable:

proc myLoop {cmdlist} {
    foreach cmd $cmdlist {
        # Execute the command in the global scope
        uplevel #0 $cmd
    }
    after 1000 [list [info coroutine] continue]
    while {[set arg [yield]] ne "continue"} {
        lappend cmdlist $arg
    }
}
coroutine addCmdInLoop myLoop $cmd1 $cmd2

Then your proposed addCmdInLoop [list myCmd $arg1 $arg2] command will work to add myCmd to any future runs of the loop.

If myLoop is already running, then I don't know how you could interrupt the loop to change the variable. Without changing the variable, then the loop would already act the same way.

You could certainly change some external to Tcl. What if your loop checked for existence of a filename instead of the value of a variable?

What you probably want to do instead is to add a trace to these variables. https://www.tcl-lang.org/man/tcl/TclCmd/trace.htm

proc do_cmd1 args {
    global cmd1
    if {$cmd1 == 1} {
        puts "cmd1 is 1"
    }
}
trace add variable cmd1 write do_cmd1

Once the trace is assigned to the variable, then the do_cmd1 proc is executed anytime a value is written to cmd1.

tcl8.6.8> set cmd1 0
0
tcl8.6.8> set cmd1 1
cmd1 is 1    <------ Look at that!!
1

However, this only runs the proc when the cmd1 variable is set. That's not really a loop behavior.

Related