From: Graham Menhennitt Date: 2013-07-21T18:23:14+09:00 Subject: Re: closing a socket while another thread is in an IO.select() call on it This is a multi-part message in MIME format. --------------070009080109090708060701 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit On 15/07/2013 18:32, Robert Klemme wrote: > > > > On Mon, Jul 15, 2013 at 9:53 AM, Graham Menhennitt > > wrote: > > Hello Rubyists, > > I have a program that opens a TCPSocket, connects it to a server, and > then creates a thread which loops until the socket closes, reading > from > the socket and processing the data read. It calls IO.select() to wait > until there is data available to read. > > > Why don't you just use a blocking read if you have a separate thread > per socket anyway? Select is only useful if you want to have a single > thread process several file descriptors. > > > Meanwhile, another thread can > close the socket in certain circumstances. If the first thread is in > IO.select() when the socket is closed, the result is unpredictable - > sometimes the select() returns and sometimes it blocks. I'm not > sure of > the circumstances that cause it to block or not - it seems random. > > > Hmmm. That sounds a bit odd. I would have expected select to return. > Maybe there's a race condition in the std lib. > > > So, is there some way to make it reliably unblock? Or is there > something > that the second thread can do to cause the select() to return (set a > flag on the socket before closing it, or something)? > > > You could work with a timeout but that seems a bit like a workaround. > > > This is with Ruby 2.0.0 p247 on Centos 5 Linux if that's significant. > > > Kind regards > > robert > > -- > remember.guy do |as, often| as.you_can - without end > http://blog.rubybestpractices.com/ Thanks for replying, Robert. I had actually simplified a bit what I told you about my use case - there was a reason for using select(). But you're right - I changed the program to use a blocking read instead, and it now works. I suspect there's some bug in select(), but I'm not sure how to reproduce it. Yes, a timeout would probably work, but not very elegant. Thank for your help, Graham --------------070009080109090708060701 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit
On 15/07/2013 18:32, Robert Klemme wrote:



On Mon, Jul 15, 2013 at 9:53 AM, Graham Menhennitt <graham@menhennitt.com.au> wrote:
Hello Rubyists,

I have a program that opens a TCPSocket, connects it to a server, and
then creates a thread which loops until the socket closes, reading from
the socket and processing the data read. It calls IO.select() to wait
until there is data available to read.

Why don't you just use a blocking read if you have a separate thread per socket anyway?  Select is only useful if you want to have a single thread process several file descriptors.
 
Meanwhile, another thread can
close the socket in certain circumstances. If the first thread is in
IO.select() when the socket is closed, the result is unpredictable -
sometimes the select() returns and sometimes it blocks. I'm not sure of
the circumstances that cause it to block or not - it seems random.

Hmmm.  That sounds a bit odd.  I would have expected select to return.  Maybe there's a race condition in the std lib.
 
So, is there some way to make it reliably unblock? Or is there something
that the second thread can do to cause the select() to return (set a
flag on the socket before closing it, or something)?

You could work with a timeout but that seems a bit like a workaround.
 
This is with Ruby 2.0.0 p247 on Centos 5 Linux if that's significant.
 
Kind regards

robert

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
Thanks for replying, Robert.

I had actually simplified a bit what I told you about my use case - there was a reason for using select(). But you're right - I changed the program to use a blocking read instead, and it now works. I suspect there's some bug in select(), but I'm not sure how to reproduce it. Yes, a timeout would probably work, but not very elegant.

Thank for your help,
    Graham
--------------070009080109090708060701--