If your Tcl script uses many afters and vwaits, sometimes it happens that vwait never returns even if its target variable is set. I didn't understand why my application get into such a situation.
Here is a sample script that causes first call of vwait never to return.
Run this script in wish.
console show rename vwait original_vwait proc vwait {var} { global last_vwait_var puts "enter vwait $var" set last_vwait_var $var original_vwait $var puts "leave vwait $var" } set last_vwait_var {} proc set_var1 {val} { global var1 puts "set var1 $val" set var1 $val } proc set_var2 {val} { global var2 puts "set var2 $val" set var2 $val } after 1000 { after 1000 { set_var1 go } vwait ::var2 } vwait ::var1 set_var2 go |
I expect the following output;
enter vwait ::var1 enter vwait ::var2 set var1 go leave vwait ::var1 set var2 go leave vwait ::var2 |
Contrary to my expection, the actual console output is;
enter vwait ::var1 enter vwait ::var2 set var1 go |
When I call "set_var2 go" interactively, the output follows,
% set var2 go go leave vwait ::var2 leave vwait ::var1 set var2 go |
This means that if you call nested vwaits, the first call of a vwait blocks until all of the nested vwait returns.
Even if you understand this characteristics of vwait, you can run into trouble in network programs. I guess this is caused by the following characteristics of a network program.
- It doesn't know when a response comes.
- It uses recursive call of vwait when resending a command on a response timeout.
- A polling loop interrupts normal sequence order.
Sorry to suck at explaining.
I made an application that communicates with multiple I/O devices which have UDP servers.
I designed it in an object-oriented way and encapsulated UDP client sockets in each of the device objects. As the UDP server device doesn't support push-notification, I had to ask their status at a certain intervals: a polling loop for each device. The polling loops are recursive call of afters. They interrupt into the normal command sequence. I guess this causes unexpected vwait call.
My design was successful in the other platforms like Ruby and C# which have built-in preemptive threads. But in Tcl, I had to place a single manager object for highly concurrent parts of the program.
Tcl has many OOP extensions. We can call Tcl as multi paradigm programming language. But as to this kind of thing, Tcl is not truely object-oriented; it forces tight dependencies between objects.
Tcl 8.6 will gain coroutines. I hope it will introduce a true OOP into Tcl.