[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Newbie question about threads and gets

Jacek Olszak

1/8/2006 5:19:00 PM

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

--
Posted via http://www.ruby-....


7 Answers

Robert Klemme

1/8/2006 5:48:00 PM

0

Jacek Olszak <jacekolszak@o2.pl> wrote:
> 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

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

Bill Kelly

1/8/2006 5:49:00 PM

0

From: "Jacek Olszak" <jacekolszak@o2.pl>
>
> 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.

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




Jacek Olszak

1/8/2006 6:16:00 PM

0

Bill Kelly wrote:
> From: "Jacek Olszak" <jacekolszak@o2.pl>
>> b=Thread.new do
>> 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.
>
> 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.)
>

Yes.. I'm using winxp currently :(

> 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


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 ;)

--
Posted via http://www.ruby-....


Jacek Olszak

1/8/2006 7:47:00 PM

0

Robert Klemme wrote:
> Jacek Olszak <jacekolszak@o2.pl> wrote:
>>
>>
>> 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
>
> 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

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

--
Posted via http://www.ruby-....


Jacek Olszak

1/8/2006 7:54:00 PM

0

Jacek Olszak wrote:
> Robert Klemme wrote:
>> Jacek Olszak <jacekolszak@o2.pl> wrote:
>>>
>>>
>>> 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
>>
>> 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
>
> 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)
>

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

--
Posted via http://www.ruby-....


Robert Klemme

1/9/2006 10:01:00 AM

0

Jacek Olszak wrote:
> Jacek Olszak wrote:
>> Robert Klemme wrote:
>>> Jacek Olszak <jacekolszak@o2.pl> wrote:
>>>>
>>>>
>>>> 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
>>>
>>> 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
>>
>> 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)
>>
>
> 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

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


Jacek Olszak

1/9/2006 7:20:00 PM

0

Robert Klemme wrote:
> Jacek Olszak wrote:
>>>>> Jacek
>>>> until
>>> with Bill solution)
>> end
>>
>> b.join
>
> Are you aware of the fact that ruby will exit as soon as the main thread
> exits?

Yes... I know...

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.
>

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

--
Posted via http://www.ruby-....