Here is another multi-threading example (now with max child control Glenn ;))

This example has the parent and child code in the same script, and takes a list of hosts from the command line and/or a file.

The child code just does a ping on each host and returns the ping time to the parent. The parent displays the colour-coded ping time.

The parent monitors the child and will detect when one takes too long to start (10 seconds) - I haven't included any checks to determine if a child has exited unexpectedly, though you can use the child PID as a lookup in the process table if that is important to you.



Break ON
$=SetOption("Explicit","ON")

; YAPP.kix - Yet Another Parallel Pinger
;
; Pass a comma seperated lists of hostsnames / IP addresses or a list in a file.
; The hosts will be pinged asynchronously, and the results displayed.

; $iMaxChild may also be set on the command line to change the limit of child
; processes which may be active at any time.

; Amendment History
; -----------------
; 20071030.13:00 R. Howarth <rhowarth@harsco.com>
; Added code to limit active child processes.
; Allow debug state to be set on command line.
; Allow maxchild to be set on command line.

If Not IsDeclared($DEBUG)
GLOBAL $DEBUG $DEBUG=0
EndIf
If Not IsDeclared($DEBUG)
Global $iMaxChild $iMaxChild=20
EndIf

Dim $sINI,$sHost,$iChildActive,$vChildPID,$vResponseTime,$vStatusCode,$iStartTicks
Dim $iMaxTicks $iMaxTicks=5000
Dim $iInterval $iInterval="0.1"
Dim $iLastHost
Dim $sActiveList
Dim $sNewList

Dim $sErrorColour, $sNormColour, $sColour

Dim $aiTime $aiTime= Split("-1,100,250,500",",")
Dim $aiColour $aiColour=Split("g+/n,y+/n,y/n,r+/n",",")

Dim $iTimeout $iTimeout=10000 ; Wait 10 seconds for a response

$sErrorColour="r+/n"
$sNormColour="w/n"

Color $sNormColour

If IsDeclared($iParentPID)
; -------------------------------------------------
; CHILD PAYLOAD - code executed for child process
; -------------------------------------------------
$sHost=$sHostList
myDEBUG("Child started for "+$sHostList)
$sINI=@SCRIPTDIR+"\YAPP_"+$iParentPID+".ini"
myDEBUG("Child started for "+$sHostList+", INI="+$sINI)
$=WriteProfileString($sINI,$sHost,"PID",@PID)
$vResponseTime=wmiPing($sHostList,$iTimeout)
$vStatusCode=@ERROR
If $vStatusCode
$vStatusCode=$vResponseTime
$vResponseTime=(-1)
EndIf
$=WriteProfileString($sINI,$sHost,"ResponseTime",$vResponseTime)
$=WriteProfileString($sINI,$sHost,"StatusCode",$vStatusCode)
Else
; -------------------------------------------------
; PARENT PAYLOAD - code executed for parent process
; -------------------------------------------------
$sINI=@SCRIPTDIR+"\YAPP_"+@PID+".ini"
Del $sINI
If Not IsDeclared($sHostList) AND Not IsDeclared($sFile)
"You must supply a comma seperated list of hosts to ping or a file containing a list"+@CRLF
" Usage: kix32 "+@SCRIPTNAME+" [$$DEBUG=0|1] [$$iMaxChild=20] $$sHostList=hostname[,hostname...] $$sFile=path_to_file"+@CRLF
Exit 0
EndIf
If Not IsDeclared($sHostLIst) Global $sHostList EndIf
If IsDeclared($sFile)
Dim $fhFile
$fhFile=FreeFileHandle()
If Open($fhFile,$sFile)
"Cannot open "+$sFile+" for reading"+@CRLF
Exit 1
EndIf
$sHost=ReadLine($fhFile)
While Not @ERROR
$sHostList=$sHostList+","+$sHost
$sHost=ReadLine($fhFile)
Loop
EndIf
$sHostList=Split($sHostList,",")
While $iChildActive OR $iLastHost<UBound($sHostList)
If ($iChildActive<$iMaxChild) AND $iLastHost<UBound($sHostList)
$iLastHost=$iLastHost+1
$sHost=$sHostList[$iLastHost]
If $sHost
myDEBUG("Starting "+$sHost)
$=WriteProfileString($sINI,$sHost,"PID","Pending")
$=WriteProfileString($sINI,$sHost,"StartTicks",@TICKS)
RUN @SCRIPTEXE+" "+@SCRIPTNAME+" $$iParentPID="+@PID+" $$sHostList="+$sHost
$iChildActive=$iChildActive+1
$sActiveList=$sActiveList+","+$sHost
EndIf
EndIf
myDEBUG("Active list: "+$sActiveList)
$sNewList=""
For Each $sHost in Split(SubStr($sActiveList,2),",")
If $sHost
$vStatusCode=ReadProfileString($sINI,$sHost,"StatusCode")
$vResponseTime=ReadProfileString($sINI,$sHost,"ResponseTime")
$vChildPID=ReadProfileString($sINI,$sHost,"PID")
$iStartTicks=ReadProfileString($sINI,$sHost,"StartTicks")
myDEBUG($sHost+": Status "+$vStatusCode)
myDEBUG($sHost+": Response "+$vResponseTime)
myDEBUG($sHost+": PID "+$vChildPID)
Select
Case $vChildPID="Completed"
; No action for completed processes
Case $vChildPID="Pending" AND (@TICKS-$iStartTicks)>$iMaxTicks
Color $sErrorColour "Child process for "+$sHost+" has failed to start in time" Color $sNormColour @CRLF
$iChildActive=$iChildActive-1
$=WriteProfileString($sINI,$sHost,"PID","Completed")
Case $vChildPID<>"0" AND $vStatusCode<>""
$=WriteProfileString($sINI,$sHost,"PID","Completed")
$iChildActive=$iChildActive-1
If $vStatusCode="0"
$sColour=$aiColour[0]
For $ = 0 To UBound($aiTime)
If CINT($vResponseTime)>=$aiTime[$] $sColour=$aiColour[$] EndIf
Next
Color $sColour $sHost+" responded in "+$vResponseTime+" ms" Color $sNormColour @CRLF
Else
Color $sErrorColour $sHost+" failed to respond, error code is "+$vStatusCode Color $sNormColour @CRLF
EndIf
Case "StillRunningOrPending"
$sNewList=$sNewList+","+$sHost
EndSelect
EndIf
Next
$sActiveList=$sNewList
If $iChildActive Sleep($iInterval) EndIf
Loop
Del $sINI
EndIf

Exit 0

Function wmiPing($sHost,Optional $Timeout)
Dim $sQuery,$oWMI,$oItem,$cItems
$sQuery = "Select ResponseTime,StatusCode From Win32_PingStatus where Address='" + $sHost + "'"
If $Timeout
$sQuery = $sQuery + " And TimeOut=" + $Timeout
EndIf
$oWMI = GetObject("winmgmts:root\cimv2")
$cItems = $oWMI.ExecQuery($sQuery)
For Each $oItem In $cItems
If (VarTypeName($oItem.StatusCode) = 'Null') $wmiPing=1 Exit 1 EndIf
If $oItem.StatusCode $wmiPing=$oItem.StatusCode Exit 1 EndIf
$wmiPing = $oItem.ResponseTime
Next
Exit 0
EndFunction

Function myDEBUG($s)
If $DEBUG "DEBUG: "+$s+@CRLF EndIf
EndFunction
; vim: sw=4 ts=4