For Programmers: Free Programming Magazines  


Home > Archive > Tcl > September 2006 > Advice for parameter passing using fileevent









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Advice for parameter passing using fileevent
af300wsm@gmail.com

2006-09-28, 7:02 pm

Hello everyone,

I'm engaged in writing a script at the moment which I believe the only
good solution is for me to use fileevent. The background is:

The script is multi-threaded and each thread is "listening" to the same
file for certain information that must be passed to it. The file that
both threads open is opened in a read-only fashion. I have a procedure
called GetCRC which takes two arguments, the file descriptor and a key
string to parse for in the file (to know if the thread is close to
finding the CRC that is important to it). The hard part of this
function for the event handler is that the key string changes each time
that GetCRC should be called.

So using the example I found at www.tcl.tk on the manual pages I don't
think will work. The example is this:
proc GetData {chan} {
if {![eof $chan]} {
puts [gets $chan]
}
}

fileevent $chan readable [list GetData $chan]

However, this would make GetData called with the exact same value every
time. In my handler, the file descriptor is always the same (as
above), but the string to look for will change. What suggestions,
other than a global variable, would there be to make this "pretty"?

Thanks for any suggestions,

Andy

Robert Heller

2006-09-28, 7:02 pm

At 28 Sep 2006 14:27:10 -0700 af300wsm@gmail.com wrote:

>
> Hello everyone,
>
> I'm engaged in writing a script at the moment which I believe the only
> good solution is for me to use fileevent. The background is:
>
> The script is multi-threaded and each thread is "listening" to the same
> file for certain information that must be passed to it. The file that
> both threads open is opened in a read-only fashion. I have a procedure
> called GetCRC which takes two arguments, the file descriptor and a key
> string to parse for in the file (to know if the thread is close to
> finding the CRC that is important to it). The hard part of this
> function for the event handler is that the key string changes each time
> that GetCRC should be called.
>
> So using the example I found at www.tcl.tk on the manual pages I don't
> think will work. The example is this:
> proc GetData {chan} {
> if {![eof $chan]} {
> puts [gets $chan]
> }
> }
>
> fileevent $chan readable [list GetData $chan]
>
> However, this would make GetData called with the exact same value every
> time. In my handler, the file descriptor is always the same (as
> above), but the string to look for will change. What suggestions,
> other than a global variable, would there be to make this "pretty"?
>
> Thanks for any suggestions,


snit can be used to create a object instance.

snit::type listener {
component channel
option -nextkey
option -datasource -readonly yes
constructor {args} {
$self configurelist $args
set channel [open "$options(-datasource)" r]
fileevent $channel readable [mymethod _GetData]
}
method _GetData {} {
if {![eof $channel]} {
set buffer [gets $channel]
# mumble $buffer $options(-nextkey) ...
$self configure -nextkey mumble
} else {
close $channel
}
}
}

set listener1 [listener %AUTO% -datasource "|fooprocess" -nextkey fookey]

...


$listener1 configure -nextkey bar

...

$listener1 configure -nextkey baz

man snit
man snitfaq
http://www.wjduquette.com/snit/

>
> Andy
>
>


--
Robert Heller -- 978-544-6933
Deepwoods Software -- Linux Installation and Administration
http://www.deepsoft.com/ -- Web Hosting, with CGI and Database
heller@deepsoft.com -- Contract Programming: C/C++, Tcl/Tk

Uwe Klein

2006-09-28, 7:02 pm

af300wsm@gmail.com wrote:
> Hello everyone,
>
> I'm engaged in writing a script at the moment which I believe the only
> good solution is for me to use fileevent. The background is:
>
> The script is multi-threaded and each thread is "listening" to the same
> file for certain information that must be passed to it. The file that
> both threads open is opened in a read-only fashion. I have a procedure
> called GetCRC which takes two arguments, the file descriptor and a key
> string to parse for in the file (to know if the thread is close to
> finding the CRC that is important to it). The hard part of this
> function for the event handler is that the key string changes each time
> that GetCRC should be called.
>

I am not quite sure i unterstood this in the manner you meant it, but:

> So using the example I found at www.tcl.tk on the manual pages I don't
> think will work. The example is this:

proc GetData4CRC {crc chan} {
> if {![eof $chan]} {
> puts [gets $chan]
> }
> }
>



interp alias {} GetData {} GetData4CRC $currentcrc
> fileevent $chan readable [list GetData $chan]


change the cmd alias when your CRC changes:

interp alias {} GetData {} GetData4CRC $nextcrc

or change the script for the fileevent on that occasion:

fileevent $chan readable [list GetData4CRC $nextcrc $chan]

uwe
Donald Arseneau

2006-09-28, 10:01 pm

af300wsm@gmail.com writes:

> I'm engaged in writing a script at the moment which I believe the only
> good solution is for me to use fileevent. The background is:
>
> The script is multi-threaded and each thread is "listening" to the same
> file for certain information that must be passed to it. The file that
> both threads open is opened in a read-only fashion.



If it is really a file, then fileevent is not suitable. Despite
its name, [fileevent] works better for pipes and sockets. Files
are always readable, even after you hit EOF. When I watch for a
file to change, I poll looking at [file mtime].

(I swear, this question made no sense to me at first because I
read "writing a script" as writing a document for actors to read!)






--
Donald Arseneau asnd@triumf.ca
af300wsm@gmail.com

2006-09-29, 8:03 am


Donald Arseneau wrote:
> af300wsm@gmail.com writes:
>
>
>
> If it is really a file, then fileevent is not suitable. Despite
> its name, [fileevent] works better for pipes and sockets. Files
> are always readable, even after you hit EOF. When I watch for a
> file to change, I poll looking at [file mtime].


This makes a lot of sense and will most likely be far less problematic
to implement.

>
> (I swear, this question made no sense to me at first because I
> read "writing a script" as writing a document for actors to read!)


Sorry to confuse you. I was under the impression that TCL is a
scripting language and that they are known as scripts. What should I
be calling them?

Andy

Bezoar

2006-09-29, 7:03 pm


af300wsm@gmail.com wrote:
> Hello everyone,
>
> I'm engaged in writing a script at the moment which I believe the only
> good solution is for me to use fileevent. The background is:
>
> The script is multi-threaded and each thread is "listening" to the same
> file for certain information that must be passed to it. The file that
> both threads open is opened in a read-only fashion. I have a procedure
> called GetCRC which takes two arguments, the file descriptor and a key
> string to parse for in the file (to know if the thread is close to
> finding the CRC that is important to it). The hard part of this
> function for the event handler is that the key string changes each time
> that GetCRC should be called.
>
> So using the example I found at www.tcl.tk on the manual pages I don't
> think will work. The example is this:
> proc GetData {chan} {
> if {![eof $chan]} {
> puts [gets $chan]
> }
> }
>
> fileevent $chan readable [list GetData $chan]
>
> However, this would make GetData called with the exact same value every
> time. In my handler, the file descriptor is always the same (as
> above), but the string to look for will change. What suggestions,
> other than a global variable, would there be to make this "pretty"?
>
> Thanks for any suggestions,
>
> Andy

As a design it is probably not a good idea for multiple threads to wait
on
the same file changing. A better way, IMHO, is to have one thread
monitor
the file and update a variable that your other threads are waiting
on. Particularily if you also write back to the same file. I havent
done
any thread based tcl programing but if I were to do it without thread
I
would do it like this :

Assume that you have a file X.txt that has a letter followed by
a number the letter never changes butthe numbers do for example:

A:1
B:2

Some exterior process changes the numbers but not the letters.

#!/opt/usr/bin/tclsh8.4
# args to doAction are dictated by the trace command see man n trace
proc doAction { name1 name2 op } {
# note switch not stricly needed as we only trace writes but...
switch -exact -- $op {
w {
# process your value here
set procname "do_[string trimleft $name1 : ]"
set varvalue [ set $name1 ]
# runs command that is based on variable traced if
# variable A is traced and its value was just written
# to be 3 then the command below would execute: do_A 3
$procname $varvalue
}
r -
u -
default {
;
}
}
}
proc do_A { value } {
global forever
puts "do_A called with Value $value"
if { $value > 100 } {
incr forever; # this will quit program
}
}
proc do_B { value } {
puts "do_B called with Value $value"
}

proc writeX { fname } {
global A B
if { [ catch { open $fname "w" } fd ] != 0 } {
error "unable to write to file $fname:$fd"
}
puts $fd "A:$A"
puts $fd "B:$B"
catch { close $fd }
}
# note this version of checkX will update both A & B so
# do_A and do_B should run every time. You can modify to
# make sure values change before updating variable
proc checkX { fname { interval 1000 } } {
global lastmtime ; # hold current mtime of monitored file
if { [ file exists $fname ] } {
set mtime [file mtime $fname ]
if { $mtime != $lastmtime } {
set lastmtime $mtime
if { [ catch { open $fname "r" } fd ] != 0 } {
error "unable to read file $fname:$fd"
}
set buffer [read $fd ]
catch { close $fd }
foreach line [ split $buffer "\n" ] {
set var [ lindex [split $line : ] 0 ]
set value [ lindex [split $line : ] 1 ]
eval set ::$var \$value ;
}
} else {
puts -nonewline "."
flush stdout
}
}
after $interval [ list checkX $fname $interval ]
}

# initial values
global A B lastmtime forever
set forever 0
set A 1
set B 100
set fname X.txt
# make our file
writeX $fname
set lastmtime [file mtime $fname ]
# assign traces only write traces active
trace variable A w doAction
trace variable B w doAction
checkX $fname 1000 ; # start the file checking once every sec
# program ends when value for A in X.txt > 100
vwait forever;
---------------END CODE ------------------------
Running. in one term and modifying file X.txt in another

$ ./traceex.tcl
............do_A called with Value 12
do_B called with Value 100
.......do_A called with Value 13
do_B called with Value 100
.............do_A called with Value 130
do_B called with Value 10
$

Donald Arseneau

2006-09-30, 4:01 am

af300wsm@gmail.com writes:

> Sorry to confuse you.


Any momentary confusion was entirely my own fault. I just
mentioned it because it was amusing.



--
Donald Arseneau asnd@triumf.ca
Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com