From: Eric Wong Date: 2009-11-25T04:54:30+09:00 Subject: Re: issues with Kernel#select Tim Pease wrote: > On Nov 22, 2009, at 7:31 PM, Eric Wong wrote: > > Tim Pease wrote: > > I'd just write a byte to a pipe (useful with signal handlers, too, see: > > http://cr.yp.to/docs/selfpipe.html) > > > > Based on the self-pipe page, here is the solution I came up with. > Please, anyone, give comments and suggestions. > > http://gist.github.com/241224 Hi Tim, I think a length argument is is required for read_nonblock. And you should probably only be reading from the receiver *after* the select. Also, the creation/check of Thread#[:select_signal_pipe] is potentially racy. I would probably create it in the parent like this: pipe = IO.pipe thr = Thread.new(pipe) do |pipe| Thread.current[:select_signal_pipe] = pipe pipe.last.syswrite('.') # wakeup parent once we know the parent can use it # ... end pipe.first.readpartial 1 # blocks until it reads '.' # after the readpartial, we know the following is set: assert(thr[:select_signal_pipe] == pipe) # ... Unlike the self-pipe example, the basic rule of thumb to avoid driving oneself nuts is that one set of threads/processes only does reads, and another set only does writes. Reading and writing to one pipe from the same thread/process anywhere outside of signal handlers gets really confusing, really quickly :> And even with the self-pipe signal handlers, all communication is one-way within any given control block. I'd also be very defensive about spurious select() wakeups (and Errno::EINTR, too, just in case). Pretty much any syscall that sleeps like select() including (but not limited to) pthread_cond_wait, poll, epoll_wait are all *potentially* susceptible to spurious wakeups, so you could be exiting a thread when you don't intend to. -- Eric Wong