Posted to tcl by patthoyts at Tue May 01 13:46:22 GMT 2007view pretty
# Demonstrate the use of asynchronous sockets with a thread pool # This expects to connect to an SMTP server. The task we are to # perform is to connect to the server, and then immediately issue a QUIT # package require Thread set program { variable uid 0 proc OnWrite {State} { upvar #0 $State state lappend state(calls) w fileevent $state(socket) writable {} } proc OnRead {State} { upvar #0 $State state set rd r if {[eof $state(socket)]} { fileevent $state(socket) readable {} set state(wait) eof lappend state(calls) re return } if {[gets $state(socket) line] != -1} { #lappend state(input) $line append rd [string length $line] if {!$state(quit)} { set state(quit) 1 puts $state(socket) "QUIT" } } else { append rd 0 } lappend state(calls) $rd } proc Test {host port} { variable uid set State [namespace current]::test[incr uid] upvar #0 $State state array set state [list tid [thread::id] quit 0 calls {}] if {[catch {set state(socket) [socket -async $host $port]} err]} { set result "ERROR: $err" } else { set state(aid) [after 5000 [list set [set State](wait) timeout]] fconfigure $state(socket) -blocking 1 -buffering line -translation crlf fileevent $state(socket) writable [list OnWrite $State] fileevent $state(socket) readable [list OnRead $State] vwait [set State](wait) after cancel $state(aid) catch {close $state(socket)} set result [array get state] } unset $State return $result } } proc Threaded {host port} { variable program # Create a pool of threads and initialize them with our code set poolid [tpool::create -maxworkers 20 -initcmd $program] # Create a number of job requests and submit the jobs to the pool. # We keep an id for each job so we can track when they complete set jids {} for {set n 0} {$n < 5000} {incr n} { lappend jids [tpool::post -nowait $poolid [list Test $host $port]] } # Wait for the jobs we submitted to complete. Collect the results # and remove completed jobs from the set of job ids so that we can # wait on the running jobs each time around the outer loop. set limit 0 array set r {} while {[llength $jids] > 0 && $limit < 5000} { set done [tpool::wait $poolid $jids] foreach id $done { #puts "[format %2d $id]: [tpool::get $poolid $id]" array set a [tpool::get $poolid $id] if {![info exists r($a(tid))]} { set r($a(tid)) 1 } else { incr r($a(tid)) } set ndx [lsearch -exact $jids $id] if {$ndx != -1} { set jids [lreplace $jids $ndx $ndx] } } incr limit } if {$limit > 999} { puts "hit limit"} # Clean up and report tpool::release $poolid foreach tid [array names r] { puts "$tid [format {% 3d} $r($tid)]\ [string repeat . [expr {int((60/400.0) * $r($tid))}]]" } return } if {!$tcl_interactive} { set r [catch [linsert $argv 0 Threaded] err] if {$r} {puts $::errorInfo} else {puts $err} exit }