pulling my hair out, why won't Kernel.sleep(0) sleep?

S

Sam Roberts

Can anybody give me any hints as to what I should be looking for? What
can cause sleep(0) to wake up?

I've got a thread that does

loop do
sleep(delay)

... do stuff, then set delay to 0 because there is no more work ...

delay = 0
end


And my loop is busy looping, sleep just won't!

Whether it does or not is triggered by changes in what appear to me to
be completely unrelated code. I'm mystified.

Thanks,
Sam
 
A

Assaph Mehr

Sam said:
Can anybody give me any hints as to what I should be looking for? What
can cause sleep(0) to wake up?

I've got a thread that does

loop do
sleep(delay)

... do stuff, then set delay to 0 because there is no more work ....

delay = 0
end


And my loop is busy looping, sleep just won't!

Whether it does or not is triggered by changes in what appear to me to
be completely unrelated code. I'm mystified.

Silly question: Is there another thread active at the same time? I
don't think a thread can sleep if it's the only one...
 
L

Luke Graham

From the docs - SIGALRM or another thread calling run. If these cases
arent relevant, could you post an example of the unrelated code?
 
N

Navindra Umanee

Sam Roberts said:
Can anybody give me any hints as to what I should be looking for? What
can cause sleep(0) to wake up?

The documentation is wrong.

sleep(0) returns immediately. sleep with *zero* arguments sleeps
forever.

static VALUE
rb_f_sleep(argc, argv)
int argc;
VALUE *argv;
{
int beg, end;

beg = time(0);
if (argc == 0) {
rb_thread_sleep_forever();
}
else if (argc == 1) {
rb_thread_wait_for(rb_time_interval(argv[0]));
}
else {
rb_raise(rb_eArgError, "wrong number of arguments");
}

end = time(0) - beg;

return INT2FIX(end);
}

Cheers,
Navin.
 
S

Shashank Date

Assaph said:
Silly question: Is there another thread active at the same time? I
don't think a thread can sleep if it's the only one...

Huh? You mean the main thread cannot sleep? Or have I mis-read your answer?

-- shanko
 
A

Assaph Mehr

Shashank said:
Huh? You mean the main thread cannot sleep? Or have I mis-read your
answer?

Perhaps I wasn't clear. The main thread can of course sleep for a
specified period. But if you do a sleep 0, it means sleep until woken
up. Ruby will check, see that there is no other thread waiting and will
thus wake the main thread again.
So if you only have one thread, you can't sleep indefinitely.

Assaph
 
A

Assaph Mehr

Assaph said:
answer?

Perhaps I wasn't clear. The main thread can of course sleep for a
specified period. But if you do a sleep 0, it means sleep until woken
up. Ruby will check, see that there is no other thread waiting and will
thus wake the main thread again.
So if you only have one thread, you can't sleep indefinitely.

Oops, looks like I was wrong. See Navindra's clarification.
 
S

Sam Roberts

Quoteing (e-mail address removed), on Fri, Feb 18, 2005 at 12:33:13PM +0900:
The documentation is wrong.

sleep(0) returns immediately. sleep with *zero* arguments sleeps
forever.

Thank you, thank you, thank you!

I had started to notice that sometimes the code busy loops, and
sometimes it doesn't, it doesn't matter whether I make any code changes,
that turned out to be unrelated.

Do you have any idea why this should be? What does Kernel.sleep(0)
actually do?

Sam
static VALUE
rb_f_sleep(argc, argv)
int argc;
VALUE *argv;
{
int beg, end;

beg = time(0);
if (argc == 0) {
rb_thread_sleep_forever();
}
else if (argc == 1) {
rb_thread_wait_for(rb_time_interval(argv[0]));
}
else {
rb_raise(rb_eArgError, "wrong number of arguments");
}

end = time(0) - beg;

return INT2FIX(end);
}

Cheers,
Navin.
 
N

Navindra Umanee

Sam Roberts said:
I had started to notice that sometimes the code busy loops, and
sometimes it doesn't, it doesn't matter whether I make any code changes,
that turned out to be unrelated.

Do you have any idea why this should be? What does Kernel.sleep(0)
actually do?

I would guess that the sleep is triggering the thread scheduler to
check the queue for eligible threads to run. Probably sometimes the
same thread is chosen and sometimes another thread.

Not 100% sure.

Cheers,
Navin.
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: pulling my hair out, why won't Kernel.sleep(0) sleep?"

|> The documentation is wrong.

Oops. I will fix.

|I had started to notice that sometimes the code busy loops, and
|sometimes it doesn't, it doesn't matter whether I make any code changes,
|that turned out to be unrelated.
|
|Do you have any idea why this should be? What does Kernel.sleep(0)
|actually do?

I guess it was busy looping, but there were other threads to work
sometimes. sleep(0) does not sleep but causes context switch.

matz.
 
P

Pit Capitain

Sam said:
I had started to notice that sometimes the code busy loops, and
sometimes it doesn't, it doesn't matter whether I make any code changes,
that turned out to be unrelated.

Do you have any idea why this should be?

Could it be that the delay variable is shared between the threads?

Regards,
Pit
 
S

Sam Roberts

Quoteing (e-mail address removed), on Fri, Feb 18, 2005 at 01:50:26PM +0900:
|Do you have any idea why this should be? What does Kernel.sleep(0)
|actually do?

I guess it was busy looping, but there were other threads to work
sometimes. sleep(0) does not sleep but causes context switch.

That describes what I saw, kindof (race conditions are inherently
weird).

Thanks,
Sam

Here's a start to the docs, but I don't know if my description is
correct!

/*
* call-seq:
- * sleep(duration=0) => fixnum
+ * sleep(duration) => fixnum
+ * sleep() => fixnum
*
- * Suspends the current thread for _duration_ seconds (which may be
- * any number, including a +Float+ with fractional seconds). Returns the actual
- * number of seconds slept (rounded), which may be less than that asked
- * for if the thread was interrupted by a +SIGALRM+, or if
- * another thread calls <code>Thread#run</code>. An argument of zero
- * causes +sleep+ to sleep forever.
- *
+ * Suspends the current thread for _duration_ seconds (which may be any
+ * number, including a +Float+ with fractional seconds). Calling sleep with
+ * no arguments causes +sleep+ to sleep "forever" - where "forever" means
+ * until it is woken up, see below. Calling sleep with an argument of
+ * +0+ causes a context switch, if another thread is ready to be
+ * scheduled.
+ *
+ * Returns the actual number of seconds slept (rounded), which may be less
+ * than that asked for if the thread was interrupted by a +SIGALRM+, or if
+ * another thread calls <code>Thread#run</code>.
+ *
+ * WHAT ABOUT OTHER SIGNALS?
+ *
* Time.new #=> Wed Apr 09 08:56:32 CDT 2003
* sleep 1.2 #=> 1
* Time.new #=> Wed Apr 09 08:56:33 CDT 2003
 
D

Daniel Berger

Navindra said:
Sam Roberts said:
Can anybody give me any hints as to what I should be looking for? What
can cause sleep(0) to wake up?

The documentation is wrong.

sleep(0) returns immediately. sleep with *zero* arguments sleeps
forever.

static VALUE
rb_f_sleep(argc, argv)
int argc;
VALUE *argv;
{
int beg, end;

beg = time(0);
if (argc == 0) {
rb_thread_sleep_forever();
}
else if (argc == 1) {
rb_thread_wait_for(rb_time_interval(argv[0]));
}
else {
rb_raise(rb_eArgError, "wrong number of arguments");
}

end = time(0) - beg;

return INT2FIX(end);
}

Cheers,
Navin.

Why are arguments being counted manually? It's less code, less error
prone, and doesn't force you to explicitly raise an ArgumentError if
the argument count is wrong.

Refactored:

/*
* :call-seq:
* sleep(numeric=nil)
*
* Suspends the current thread for +numeric+ seconds (which may be a
* Float with fractional seconds. Returns the actual number of seconds
* slept, rounded, which may be less than what was asked for if the
* thread was interrupted by a SIGALARM or if another thread calls
* Thread#run.
*
* If no argument is provided then it will sleep forever.
*/
static VALUE
rb_f_sleep(argc, argv)
int argc;
VALUE *argv;
{
int beg, end;
VALUE rbNum;

beg = time(0);

rb_scan_args(argc,argv,"01",&rbNum);

if(NIL_P(rbNum)){
rb_thread_sleep_forever();
}
else{
rb_thread_wait_for(rb_time_interval(rbNum));
}

end = time(0) - beg;

return INT2FIX(end);
}
 
T

ts

D> Why are arguments being counted manually?

it's faster :)

D> if(NIL_P(rbNum)){
D> rb_thread_sleep_forever();
D> }

it don't do the same thing :)

uln% ruby -e 'sleep(nil)'
-e:1:in `sleep': can't convert NilClass into time interval (TypeError)
from -e:1
uln%



Guy Decoux
 
D

Daniel Berger

ts said:
D> Why are arguments being counted manually?

it's faster :)

D> if(NIL_P(rbNum)){
D> rb_thread_sleep_forever();
D> }

it don't do the same thing :)

uln% ruby -e 'sleep(nil)'
-e:1:in `sleep': can't convert NilClass into time interval (TypeError)
from -e:1
uln%

I'm confused - what conversion is it trying to do? I thought these two
were equivalent:

if(NIL_P(rbNum))

if(Qnil == rbNum)

No?

Regards,

Dan
 
T

ts

D> I'm confused - what conversion is it trying to do? I thought these two
D> were equivalent:

D> if(NIL_P(rbNum))

D> if(Qnil == rbNum)

if you want to write the same with rb_scan_args(), you must write

if (rb_scan_args(argc, argv, "01", &rbNum)) {
rb_thread_wait_for(rb_time_interval(rbNum));
}
else {
rb_thread_sleep_forever();
}


and you see that the ruby version is faster :)


Guy Decoux
 
D

Daniel Berger

ts said:
D> I'm confused - what conversion is it trying to do? I thought these two
D> were equivalent:

D> if(NIL_P(rbNum))

D> if(Qnil == rbNum)

if you want to write the same with rb_scan_args(), you must write

if (rb_scan_args(argc, argv, "01", &rbNum)) {
rb_thread_wait_for(rb_time_interval(rbNum));
}
else {
rb_thread_sleep_forever();
}


and you see that the ruby version is faster :)


Guy Decoux

First things first. You're skirting the issue. It SHOULD work. There
is some sort of side effect happening, because the error is NOT coming
from process.c. I added some debug print statements directly into
process.c and rebuilt. I can't even get to that point before the error
is raised. This smells like a bug and/or some kind of global setting
being used some where.

Second, counting argc is not significantly faster than using
rb_scan_args(). Using the following code, counting argc was faster by
by .01 to .05 seconds over *ONE MILLION* iterations. That's 5.0e-008
per iteration. Rather insignificant don't you think?

/* foo.c
*
* The purpose of this class is to test the speed of manual counting
* of argc vs using rb_scan_args().
*/
#include "ruby.h"
#include <stdlib.h>

VALUE some_func(int num);
int other_func(VALUE rbNum);

VALUE some_func(int num){
VALUE rbNum = INT2FIX(num);
return rbNum;
}

int other_func(VALUE rbNum){
int y = FIX2INT(rbNum);
return y;
}

static VALUE test_scan(int argc, VALUE* argv){
VALUE rbNum;

rb_scan_args(argc,argv,"01",&rbNum);

if(NIL_P(rbNum)){
some_func(55);
}
else{
other_func(argv[0]);
}

return rbNum;
}

static VALUE test_count(int argc, VALUE* argv){
if(argc == 0){
some_func(55);
}
else if(argc == 1){
other_func(argv[0]);
}
else{
rb_raise(rb_eStandardError,"Wrong number of arguments");
}

return Qnil;
}

void Init_foo(){
VALUE cFoo = rb_define_class("Foo",rb_cObject);
rb_define_singleton_method(cFoo,"test_scan",test_scan,-1);
rb_define_singleton_method(cFoo,"test_count",test_count,-1);
}

# extconf.rb
require "mkmf"
create_makefile("foo")

# test_basic.rb
# Proof that you ought to be able to send 'nil'
# Adding debug print statements to the C code proves that it
# does what I intend.

$:.unshift Dir.pwd

require "foo"

Foo.test_scan(5) # works
Foo.test_scan # works
Foo.test_scan(nil) # works (!)

# test_speed.rb
$LOAD_PATH.unshift Dir.pwd

require "foo"
require "benchmark"
include Benchmark

bm do |x|
x.report("scan"){
1000000.times{ Foo.test_scan }
}
x.report("count"){
1000000.times{ Foo.test_count }
}
end

Results of benchmark using on Solaris 9, gcc 3.4.2, 500Mhz Sparc Ultra
IIe, 512 MB RAM:

user system total real
scan 3.220000 0.000000 3.220000 (3.224927)
count 3.170000 0.000000 3.170000 (3.179761)

Regards,

Dan
 

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. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,731
Messages
2,569,432
Members
44,832
Latest member
GlennSmall

Latest Threads

Top