Start a program, get it's output, then kill it. while"multithreading"...

D

Deadolus

Hi everybody,

i'd like to program a gui for iperf (http://sourceforge.net/projects/
iperf), it should run under windows And *NIX and I'm using fox as my
gui toolkit, I'll use some extra calculations to get the parameters,
that's why I can't use an already existing gui for iperf.
I already designed the gui and I'm now moving to connect the different
widgets to it's functions.
After you set all your parameters (size of packet, bandwith,
time, ...) I want to press a button and it should start iperf and
parallely read the it's output, so I can display some statistics
(running time and, on server side, the packet loss, maybe more).
So what should I program to do this?
I read about multithreading, IO.popen would be perfect, but how can I
kill iperf when I want to quit, before iperf ran out of time?
I think threads could also work (especially because one can kill
threads, if no longer used so the program would be terminated), but
what do I do to start the iperf?
I'm new to this subject and would appreciate any help on this!

Thanks in advance,

Deadolus
 
R

Robert Klemme

2008/1/18 said:
i'd like to program a gui for iperf (http://sourceforge.net/projects/
iperf), it should run under windows And *NIX and I'm using fox as my
gui toolkit, I'll use some extra calculations to get the parameters,
that's why I can't use an already existing gui for iperf.
I already designed the gui and I'm now moving to connect the different
widgets to it's functions.
After you set all your parameters (size of packet, bandwith,
time, ...) I want to press a button and it should start iperf and
parallely read the it's output, so I can display some statistics
(running time and, on server side, the packet loss, maybe more).
So what should I program to do this?
I read about multithreading, IO.popen would be perfect, but how can I
kill iperf when I want to quit, before iperf ran out of time?
I think threads could also work (especially because one can kill
threads, if no longer used so the program would be terminated), but
what do I do to start the iperf?

First of all killing a thread won't help because the process is in no
way attached to a Ruby thread (btw, this would also be true if Ruby
was using native threads).

You can however use a thread to read output from IO.popen. For
example, you could stuff lines into a Queue which is read from your UI
thread and displayed. Or whatever you want do do with it.

About the killing I am not sure. With a quick check I did not find a
proper way to get the PID of the child process with IO.popen. If
there is no way you could use popen with "-" as command (i.e. start a
child process), have that writ out the current PID (in $$) to stdout
and exec the process you want to start. The parent would then have to
read the child PID first and remember it somewhere.

Kind regards

robert
 
D

Deadolus

2008/1/18, Deadolus <[email protected]>:




First of all killing a thread won't help because the process is in no
way attached to a Ruby thread (btw, this would also be true if Ruby
was using native threads).

You can however use a thread to read output from IO.popen. For
example, you could stuff lines into a Queue which is read from your UI
thread and displayed. Or whatever you want do do with it.

About the killing I am not sure. With a quick check I did not find a
proper way to get the PID of the child process with IO.popen. If
there is no way you could use popen with "-" as command (i.e. start a
child process), have that writ out the current PID (in $$) to stdout
and exec the process you want to start. The parent would then have to
read the child PID first and remember it somewhere.

Kind regards

robert

I think I found the solution, this is a example script:

io = IO.popen("ping google.ch") #open a new io
thread = Thread.new(io) {while !io.closed? do Thread.current["line"] =
io.readline end}#ALWAYS read current line of io
i=0 #example code...
while i<10 do
puts thread["line"]
puts thread.status #puts out "sleep", so it's running...
i+=1
sleep(1)
end
io.close #close io
thread.status #puts out "nil" so it's terminated

Seems like you easily can close a io just by "close".
At least it isn't in my ps aux list any more...
But I just tested under linux so far, so I can't say if this also
works under windows (I currently have some problems with my windows
box).
What do you think about this solution?
If anyone has a better solution, I'm still interested....
 
S

Stephen Lewis

...

About the killing I am not sure. With a quick check I did not find
a proper way to get the PID of the child process with IO.popen. If
...

It's a little hard to find until you already know where it is, but
IO#pid might come in handy here :)
 
R

Robert Klemme

It's a little hard to find until you already know where it is, but
IO#pid might come in handy here :)

Thanks! I use #popen too infrequently and when I use it I do not
normally fiddle with the process directly.

Kind regards

robert
 
D

Deadolus

Thanks! I use #popen too infrequently and when I useitI do not
normally fiddle with the process directly.

Kind regards

robert

I wasn't really happy about my solution, so I continued
experimenting.
I now have something, which I'm quite happy about, I'll post it here,
maybe some people have the same problems as I had.
I expanded the normal IO class:

#-------------------File
OwnIO.rb--------------------------------------
module OwnIO

def killed? #nil if not killed, pid of IO if killed
#I think we do not need this, please correct me, if I am wrong:
#if(self.class != IO) then raise "Wrong type of Input variable, is
#{self.class} but should be IO!" end
begin

Process.waitpid(self.pid,Process::WNOHANG)
rescue Errno::ECHILD #rescue if process is already terminated
self.pid
end
end

def kill #kill a IO (you still have to close it)
Process.kill("KILL",self.pid)
end

end

class IO #add my own IO module to the normal IO class
include OwnIO
end

#---------EOF----------------------------------------------

And here is a short example script (how I'll implement it in my GUI
more or less):

#-------------------test.rb---------------------------------
require "OwnIO.rb"
STDOUT.sync = true
old = nil #old output
i = 0
io = IO.popen("ping google.ch")
io.sync = true

t = Thread.new() {while !io.killed? do Thread.current["line"] =
io.readline end}#first doesn't output all lines (Thread creation too
slow?)
while !io.killed? do
if t["line"]!=old then#only react to changes of the line
old = t["line"]
puts t["line"]#puts the current line
if i==20 then ##kill the io after 20 lines have been received
io.kill
end
i+=1;
end
end
puts "Killed"
#----------------------------
EOF----------------------------------------

The two functions "killed?" and "kill" are self explanatory, and seem
to work nice.
But at least "killed?" could have some improvements...
So if anybody has some improvements/suggestions to the code: go ahead!

Regards, Deadolus
 
A

ara.t.howard

So if anybody has some improvements/suggestions to the code: go ahead!

if you care about stderr this won't work on windows or nix. threads,
io, and guis will hang you on windows unless you really know what you
are doing. for a portable way to start a process, capture it's
stdout/stderr, and have a handle on the pid see my systemu lib - it's
the only thing that'll work afaikt (read archives)

regards.

a @ http://drawohara.com/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top