From: Robert Klemme Date: 2011-02-10T23:46:52+09:00 Subject: Re: What should TCPSocket#close do to a blocked #readline? On Thu, Feb 10, 2011 at 12:59 PM, Alex Young wrote: > > Take the following code: > >  require 'socket' >  require 'thread' > >  server = TCPServer.new("localhost", 0) >  serv_thread = Thread.new{ server.accept } >  sleep(0.1) >  sock = TCPSocket.new("localhost", server.addr[1]) > >  q = Queue.new >  client_thread = Thread.new{ >    begin >      sock.readline >    rescue StandardError => e >      q.push(e) >    end >  } > > >  sleep(0.1) while client_thread.status == "run" >  sock.close >  # client_thread.wakeup rescue nil >  err = q.pop >  client_thread.join >  fail "Failure!" unless err.is_a?(IOError) >  puts "Success!" > > > So, we've got one thread blocked on a #readline, and another thread > closes the socket out from under it. On 1.8.7-p302, this completes > successfully. On 1.9.2-p136, it hangs at q.pop. I cannot confirm this: 15:40:10 Temp$ ruby19 -v ruby 1.9.2p136 (2010-12-25 revision 30365) [i386-cygwin] 15:40:50 Temp$ ruby19 s.rb # Success! 15:41:31 Temp$ cat s.rb require 'socket' require 'thread' server = TCPServer.new("localhost", 0) serv_thread = Thread.new{ server.accept } sleep(0.1) sock = TCPSocket.new("localhost", server.addr[1]) q = Queue.new client_thread = Thread.new{ begin sock.readline q.push "OK" rescue StandardError => e p e q.push(e) end } sleep(0.1) while client_thread.status == "run" sock.close # client_thread.wakeup rescue nil err = q.pop # client_thread.join fail "Failure!" unless err.is_a?(IOError) puts "Success!" 15:41:36 Temp$ > If I uncomment the client_thread.wakeup call, both complete (although > the rescue is necessary to prevent a ThreadError on 1.8.7). > > Is this expected? Which is "correct"? Hm... I would expect your 1.9.2 to also throw. Btw, one thing is odd about your test case: you have two mechanisms to synchronize threads - you read from the queue and you join client_thread. If you really only want to track status of the thread you could as well use Thread#value: client_thread = Thread.new{ begin sock.readline nil rescue StandardError => e e end } err = client_thread.value Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/