Ruby Mulithreading


#1

Hi

I’ve been recently encountered a major problem with a program i am
coding.
Main in my program outputs a menu with some cases you can choose,
1,2,3… so i have a gets at the end of the menu. However, my program
also checks for timestamps with a seperate thread (thread 2). And it
appeared that the thread bugged when I used gets, since i have 3 if
conditions in my thread 2, and if i for example replace gets with
sleep(200), the if conditions runs as it should. But when I have the
gets, it never runs. Later I found out that there is appearently a bug
in Ruby with standard I/O and threads in Windows?

So, how can i workaround this bug? Is there any alternative method for
input or so?

Thanks


#2

From: “Hello There” removed_email_address@domain.invalid

in Ruby with standard I/O and threads in Windows?
It’s more like a bug (or “misfeature”) of Windows, in that select() is
broken for file handles and pipes. Prior to ruby 1.9, ruby uses
select() internally to wait for I/O while performing its own thread
scheduling.

So, how can i workaround this bug? Is there any alternative method for
input or so?

Ruby 1.9 will work, since 1.9 now uses OS native threads. So gets()
will block its thread, without blocking the whole process.

If you need to use 1.8, it is possible to write a nonblocking gets on
windows using kbhit/getch:


require 'Win32API'

class Win32GetsNonblock
  @@kbhit_proc = Win32API.new("msvcrt", "_kbhit", [], 'I')
  @@getch_proc = Win32API.new("msvcrt", "_getch", [], 'I')

  class << self
    def gets
      str = ""
      begin
        ch = getch
        ch = ?\n if ch == ?\r
        str << ch.chr
      end until ch == ?\n
      str
    end

    def kbhit
      @@kbhit_proc.call != 0
    end

    def getch
      sleep 0.1 until kbhit
      @@getch_proc.call
    end
  end
end


# example.......

th = Thread.new { loop {puts Time.now; sleep 1} }

x = Win32GetsNonblock.gets
p x

Note, I have only tried the above on
ruby 1.8.4 (2005-12-24) [i386-mswin32]

Hope this helps,

Bill


#3

Hi
Thank you very much for answer.

What if i want the code to be able to run on linux aswell?

Also, I tried installing Ruby 1.9.1, but some of the libs i use e.g
Nokogiri is appearently not supported in 1.9.

best regards


#4

From: “Hello There” removed_email_address@domain.invalid

What if i want the code to be able to run on linux aswell?

gets doesn’t block other threads on Linux, because select() isn’t
broken on Linux.

So… one possibility would be to define a nonblocking gets method,
which on Linux is just aliased to the original gets, since it works.
But on windows, uses the nonblocking implementation.


if PLATFORM =~ /mswin/
  def getsnb
    # do nonblocking gets using kbhit/getch as in previous email
  end
else
  alias :getsnb :gets
end


# Example...

x = getsnb

Perhaps a cleaner approach would be to make a module which
provides a replacement for gets on windows only. On non-windows
systems, the module would be empty.


module NonblockGets
  if PLATFORM =~ /mswin/
    def gets
      # do nonblocking gets using kbhit/getch as in previous email
    end
  end
end


# Example....

class MyClass
  include NonblockGets

  def my_method
    x = gets  # on windows, this will be the gets defined in 
NonblockGets module
  end
end

Hope this helps,

Bill