Skip to content

Instantly share code, notes, and snippets.

@garybernhardt
Last active November 23, 2022 12:42
Show Gist options
  • Save garybernhardt/2963229 to your computer and use it in GitHub Desktop.
Save garybernhardt/2963229 to your computer and use it in GitHub Desktop.
A queue that you can pass to IO.select.
# A queue that you can pass to IO.select.
#
# NOT THREAD SAFE: Only one thread should write; only one thread should read.
#
# Purpose:
# Allow easy integration of data-producing threads into event loops. The
# queue will be readable from select's perspective as long as there are
# objects in the queue.
#
# Implementation:
# The queue maintains a pipe. The pipe contains a number of bytes equal to
# the queue size.
#
# Example use:
# queue = SelectableQueue.new
# readable, _, _ = IO.select([queue, $stdin])
# print "got #{queue.pop}" if readable.contain?(queue)
#
class SelectableQueue
def initialize
@queue = Queue.new
@read_io, @write_io = IO.pipe
end
def <<(o)
@queue << o
# It doesn't matter what we write into the pipe, as long as it's one byte.
@write_io << '.'
self
end
def pop(nonblock=false)
o = @queue.pop(nonblock)
@read_io.read(1)
o
end
def to_io
@read_io
end
end
require_relative "../selectable_queue"
describe SelectableQueue do
let(:q) { SelectableQueue.new }
it "queues objects" do
q << 1 << 2
q.pop.should == 1
q.pop.should == 2
expect { q.pop(true) }.to raise_error(ThreadError)
end
it "is not selectable when empty" do
readable, _, _ = IO.select([q], nil, nil, 0)
readable.should == nil
end
it "is selectable when there are objects in it" do
q << 1
readable, _, _ = IO.select([q], nil, nil, 0)
readable.should == [q]
end
it "is not selectable after being emptied" do
q << 1
q.pop
readable, _, _ = IO.select([q], nil, nil, 0)
readable.should == nil
end
end
@ms-ati
Copy link

ms-ati commented Sep 28, 2017

👍 Thanks for sharing this

@grudzien
Copy link

grudzien commented Jan 5, 2018

I know this was written some time ago but the array variable readable does not have a method called .contain? did you mean .member? or .include?. I don't remember if there was a .contain? in the past. I was testing your example on Ruby 2.3.3 and it was throwing an exception on that call in a thread.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment