Newbie question about threads and gets

Discussion in 'Ruby' started by Jacek Olszak, Jan 8, 2006.

  1. Jacek Olszak

    Jacek Olszak Guest

    Hi everyone...

    I've a simple question - how can I write an application with two
    threads, where first thread reads the user input. I want both threads to
    run SIMULTANEOUSLY.
    So .. here is my code:

    a=Thread.new do
    $stdin.gets
    end

    b=Thread.new do
    5.times do
    print "b"
    $stdout.flush
    Thread.pass
    end
    end

    a.join
    b.join

    Unfortunelty "gets" block my whole application - the "b" thread waits
    until user writes something to the stdin. But I want the b thread not
    wait and run at the same time.

    Thanks
    Jacek
     
    Jacek Olszak, Jan 8, 2006
    #1
    1. Advertisements

  2. I'm not sure what you're up to in the end but I'd start with commenting
    Thread.pass. Ruby normally schedules threads automatically and thus you
    usually don't need Thread.pass. And btw, you can do $stdout.sync=true -
    which removes the necessity of invoking flush.

    Ah, and another note: the first thread blocks the whole app until you enter
    something simply because it's joined on. The main thread won't exit until
    you enter something.

    HTH

    robert
     
    Robert Klemme, Jan 8, 2006
    #2
    1. Advertisements

  3. Jacek Olszak

    Bill Kelly Guest

    This tends to be a problem with Windows ruby. It seems unlikely to be
    resolved until Ruby gets native threads (on the horizon with YARV.)

    Here's how I've worked around it. If anyone knows a better way, please
    share:

    if RUBY_PLATFORM =~ /win32/
    require 'Win32API'
    $win32_console_kbhit = Win32API.new("msvcrt", "_kbhit", [], 'I')
    def console_input_ready?
    $win32_console_kbhit.call != 0
    end
    def nonblocking_stdin_gets
    sleep(0.1) until console_input_ready?
    $stdin.gets # don't bother to use getc, it also blocks until user hits <return>
    end
    else
    def nonblocking_stdin_gets
    $stdin.gets # it just works, on unix
    end
    end

    So you can use nonblocking_stdin_gets in place of $stdin.gets. It's an
    imperfect solution, though. It will be nonblocking _until_ the user starts
    typing. Then it will block until they hit <return>. (Note, I've tried doing
    it character-by-character, with $stdin.getc or $stdin.sysread(1), but it
    still blocks until the user hits <return>.) There's probably a way to put
    the windows console into unbuffered mode, which would improve this
    hack (so we could use $stdin.getc in conjunction with console_input_ready?.)

    Anyway, hope this helps . . .

    Regards,

    Bill
     
    Bill Kelly, Jan 8, 2006
    #3
  4. Jacek Olszak

    Jacek Olszak Guest

    Yes.. I'm using winxp currently :(

    Thanks a lot Bill! Maybe it is not a perfect solution, but quite useful
    for me at the moment :)

    P.S. I'm going to change my os till midnight ;)
     
    Jacek Olszak, Jan 8, 2006
    #4
  5. Jacek Olszak

    Jacek Olszak Guest

    First of all... thanks for help. I've set sync to true and remove
    Thread.pass. (but as you said these things won't fix the problem). So
    I've removed _a.join_ call and now everything works! (but wait a second
    - only on my newly installed linux :(, on windows works only with Bill
    solution)

    Regards
    Jacek
     
    Jacek Olszak, Jan 8, 2006
    #5
  6. Jacek Olszak

    Jacek Olszak Guest

    I don't know hot it is possible but this code works on windows too :

    $stdout.sync=true

    a=Thread.new do
    50.times do
    $stdin.gets
    puts "=="+$aaa.to_s
    end
    end

    b=Thread.new do
    10000000000.times do |i|
    $aaa=i
    # Thread.pass - when uncomment this - works on linux only, when
    comment this - works on windows only :)
    end

    end

    b.join


    Thanks a lot once again!
    Jacek
     
    Jacek Olszak, Jan 8, 2006
    #6
  7. Are you aware of the fact that ruby will exit as soon as the main thread
    exits? So your difference might well be timing related.

    10:58:20 [source]: ruby -e 'Thread.new { sleep 1; puts "end" }'
    10:59:22 [source]: ruby -e 'Thread.new { sleep 1; puts "end" }; sleep 2'
    end
    10:59:28 [source]:

    Notice how the first piece doesn't print? That's because the main thread
    simply exits killing the sleeping first thread.

    Again, I don't know what you're up to so it's difficult to provide advice
    how to do it right. In your simple example thread a is pointless IMHO -
    you could do that as well in the main thread.

    Cheers

    robert
     
    Robert Klemme, Jan 9, 2006
    #7
  8. Jacek Olszak

    Jacek Olszak Guest

    Yes... I know...

    So your difference might well be timing related.
    The problem is with windows - gets command blocks every thread in
    application.
    In my example the b thread is automatically started. In the same time in
    a thread, gets command waits for user input. But in fact, on windows
    platform gets command blocks everything, so nothing is done in "b"
    thread. And I want to write an application which do something in the
    background, and wait for user input at the same time (on windows it's
    currently impossible :( )

    Regards
    Jacek
     
    Jacek Olszak, Jan 9, 2006
    #8
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.