B
Brian Candler
I've been away from this list for a while, so I don't know what the current
thinking is behind the scoping rules for block-local variables, and whether
they're likely to be changed.
But I've just been bitten by this. Have a look at the following code, and
see if you can see what's wrong with it just by inspection. It accepts TCP
connections on a socket, and starts a server in a thread for each one. It's
a nice pattern for TCP servers.
-----------------------------------------------------------------------
require 'socket'
module MyModule
def run
puts "Hello, world!"
sleep 10
puts "Goodbye"
# ... could do other stuff
end
end
port = (ARGV[0] || 7000).to_i
bind = (ARGV[1] || '0.0.0.0')
server = TCPserver.new(bind, port)
# For each connection, add our 'run' method to the I/O object and run it
# in its own thread
while (session = server.accept)
session.extend MyModule
Thread.new do
begin
session.run
rescue Exception => e
STDERR.puts "Caught exception: #{e}\n\t#{e.backtrace.join("\n\t")}"
ensure
session.close
end
end
end
-----------------------------------------------------------------------
To demonstrate the problem: run it in one window, and then in two further
windows type "telnet localhost 7000" in each, less than 10 seconds apart.
Watch the second one fail, and also see an exception reported by the server.
After quite a bit of head-scratching, and boiling my server down to the
simple code shown above, I managed to work out what was wrong and fix it.
However, I wonder if the language could have helped me more here? "ruby -w"
didn't spot any problem (although perhaps it would be hard for it to do so).
I think this is a type of problem which unit testing is unlikely to find,
unless you are specifically aware of it.
Regards,
Brian.
v
v
v
v
v
The fix:
-----------------------------------------------------------------------
...
while (s = server.accept)
s.extend MyModule
Thread.new(s) do |session|
begin
...
thinking is behind the scoping rules for block-local variables, and whether
they're likely to be changed.
But I've just been bitten by this. Have a look at the following code, and
see if you can see what's wrong with it just by inspection. It accepts TCP
connections on a socket, and starts a server in a thread for each one. It's
a nice pattern for TCP servers.
-----------------------------------------------------------------------
require 'socket'
module MyModule
def run
puts "Hello, world!"
sleep 10
puts "Goodbye"
# ... could do other stuff
end
end
port = (ARGV[0] || 7000).to_i
bind = (ARGV[1] || '0.0.0.0')
server = TCPserver.new(bind, port)
# For each connection, add our 'run' method to the I/O object and run it
# in its own thread
while (session = server.accept)
session.extend MyModule
Thread.new do
begin
session.run
rescue Exception => e
STDERR.puts "Caught exception: #{e}\n\t#{e.backtrace.join("\n\t")}"
ensure
session.close
end
end
end
-----------------------------------------------------------------------
To demonstrate the problem: run it in one window, and then in two further
windows type "telnet localhost 7000" in each, less than 10 seconds apart.
Watch the second one fail, and also see an exception reported by the server.
After quite a bit of head-scratching, and boiling my server down to the
simple code shown above, I managed to work out what was wrong and fix it.
However, I wonder if the language could have helped me more here? "ruby -w"
didn't spot any problem (although perhaps it would be hard for it to do so).
I think this is a type of problem which unit testing is unlikely to find,
unless you are specifically aware of it.
Regards,
Brian.
v
v
v
v
v
The fix:
-----------------------------------------------------------------------
...
while (s = server.accept)
s.extend MyModule
Thread.new(s) do |session|
begin
...