C extension and Ruby threads

Hi all,
I've found something a bit weird while trying to make a C extension
wrapping a custom network library :
- My extension creates a BaseClient class with a method 'receive' (it
basically wait a response from a server for a given period of time)
- I created a ruby class Client that inherits from BaseClient. In the
constructor of this class, I create a thread that loops on the method
receive(). Note that in my C code, the receive function does a
WaitForSingleObject (Windows equivalent of pthread_cond_wait ) with a
timeout of 100ms

My problem is that even if my reception thread is in a wait state, my
main thread doesn't run smoothly (it freezes while the other thread
calls Client#receive).
I tried to place a Thread.pass between each iteration of the loop,
that's a little better but still far from what I expected.

Tested on Ruby 1.8.7 and ruby 1.9.1 (thought that native threads would
solve my problem, but not at all).

My code is the following :

require 'TestClientBase'
  class Client < ClientBase

      def initialize()
        @thread = Thread.new(self) {
          >client>
          fin = false
          while fin != true
           msg = client.receive(100)
           case msg
            when TIME_OUT
               puts ("Timeout")
            when SERV_CLOSED
               fin = true
           end
           Thread.pass
          end
        }
        @thread.priority = -1
      end
      def wait()
          @thread.join(10.0)
      end
  end

client = Client.new

100.times {
  puts "Time=#{Time.now}"
}

client.wait()

Thanks for you replies.

···

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

In 1.8, there's not really a good way to address this unless you can
convert the object you're waiting on to a file descriptor suitable to
wait on with rb_thread_select().

In 1.9, there is additionally an API function --
rb_thread_blocking_region -- which you can use to wrap a function which
needs to block (provided that the function doesn't touch the Ruby
interpreter or Ruby objects in any way); rb_thread_blocking_region
permits other threads to continue while the function you pass to it
blocks.

Either approach should also permit you to simply block without polling
with a timeout as you do now.

-mental

···

On Sun, 2009-07-26 at 07:18 +0900, John Bob wrote:

- I created a ruby class Client that inherits from BaseClient. In the
constructor of this class, I create a thread that loops on the method
receive(). Note that in my C code, the receive function does a
WaitForSingleObject (Windows equivalent of pthread_cond_wait ) with a
timeout of 100ms

- I created a ruby class Client that inherits from BaseClient. In the
constructor of this class, I create a thread that loops on the method
receive(). Note that in my C code, the receive function does a
WaitForSingleObject (Windows equivalent of pthread_cond_wait ) with a
timeout of 100ms

How about rb_thread_polling() and WaitForSingleObject(handle, 0)?

  while ((result = WaitForSingleObject(handle, 0)) == WAIT_TIMEOUT) {
    /* The current thread sleeps 0.06 second to make a time for other
threads to run. */
    rb_thread_polling();
  }
  if (result == WAIT_OBJECT_0) {
    ...

In 1.8, there's not really a good way to address this unless you can
convert the object you're waiting on to a file descriptor suitable to
wait on with rb_thread_select().

rb_thread_select() is best for file descriptors on Unix. But on Windows,
it works only for sockets. It assumes normal files are always readable/writable.
See a comment in rb_w32_select() in win32/win32.c. Thus it is unusable in
this case.

In 1.9, there is additionally an API function --
rb_thread_blocking_region -- which you can use to wrap a function which
needs to block (provided that the function doesn't touch the Ruby
interpreter or Ruby objects in any way); rb_thread_blocking_region
permits other threads to continue while the function you pass to it
blocks.

Agree. It is better than rb_thread_polling() in 1.9.

···

On Sun, Jul 26, 2009 at 9:01 AM, MenTaLguY<mental@rydia.net> wrote:

On Sun, 2009-07-26 at 07:18 +0900, John Bob wrote:

Either approach should also permit you to simply block without polling
with a timeout as you do now.

-mental

Sorry, rb_thread_polling() returns immediately if only one thread runs.
rb_thread_wait_for() should be used instead.

while ((result = WaitForSingleObject(handle, 0)) == WAIT_TIMEOUT) {
    struct timeval tv;
    tv.sec = 0;
    tv.usec = 100000;
rb_thread_wait_for(rv); /* sleep 0.1 second */
}

···

On Sun, Jul 26, 2009 at 8:47 PM, KUBO Takehiro<kubo@jiubao.org> wrote:

How about rb_thread_polling() and WaitForSingleObject(handle, 0)?

Takehiro Kubo wrote:

···

On Sun, Jul 26, 2009 at 8:47 PM, KUBO Takehiro<kubo@jiubao.org> wrote:

How about rb_thread_polling() and WaitForSingleObject(handle, 0)?

Sorry, rb_thread_polling() returns immediately if only one thread runs.
rb_thread_wait_for() should be used instead.

while ((result = WaitForSingleObject(handle, 0)) == WAIT_TIMEOUT) {
    struct timeval tv;
    tv.sec = 0;
    tv.usec = 100000;
    rb_thread_wait_for(rv); /* sleep 0.1 second */
}

I used the rb_thread_blocking_region method, seems to work like a charm!
Thanks a lot for your help.
--
Posted via http://www.ruby-forum.com/\.