[Kde-bindings] Using threads with QtRuby

Uriel uriel at inbox.ru
Fri Feb 5 19:37:16 UTC 2010


> But you only get a log of vitual method callbacks if you want them. 
> The are
> various levels and types of debug output and it is quite easy to 
> customize.
> Maybe it is a bit over complicated but you will only get virtual method
> callbacks logged if one of the things you pass to 
> Qt::Internal.setDebug() is
> QTDB_VIRTUAL.
Yes, I know about different debug levels, thank you. But sometimes I 
become paranoid and explicitly set level to QTDB_ALL complicating all 
the thing around myself. :) So, may be it's not a really big deal.
Here is the small patch for qtruby4.rb in trunk with comments. I've 
tested it on different amount of threads and everything seems to be ok.

--- qtruby4.rb    2010-02-06 00:20:35.056527428 +0500
+++ qtruby4.rb    2010-02-06 00:31:59.293534007 +0500
@@ -43,6 +43,17 @@
          @@debug_level
      end

+    # We're causing main thread to sleep for some really small amount 
of time time to force Ruby VM do the scheduling
+    @@ruby_thread_sleep_time = 1e-9
+
+    def Qt.ruby_thread_sleep_time
+        @@ruby_thread_sleep_time
+    end
+
+    def Qt.ruby_thread_sleep_time=(time)
+        @@ruby_thread_sleep_time = time
+    end
+
      module Internal
          #
          # From the enum MethodFlags in qt-copy/src/tools/moc/generator.cpp
@@ -454,6 +465,26 @@
      end

      class Application < Qt::Base
+        private
+        def enable_ruby_threads
+          # Start timer if only it hasn't been started yet
+          return unless @ruby_threads_timer_id == -1
+
+          @ruby_threads_timer_id = startTimer 0
+        end
+
+        def disable_ruby_threads
+          # Stop timer only if we have main thread and just one custom 
which will be stopped right after this call
+          return unless Thread.list.count == 2
+
+          killTimer @ruby_threads_timer_id
+          @ruby_threads_timer_id = -1
+        end
+        protected
+        def timerEvent(ev)
+          sleep Qt::ruby_thread_sleep_time
+        end
+        public
          def initialize(*args)
              if args.length == 1 && args[0].kind_of?(Array)
                  super(args.length + 1, [$0] + args[0])
@@ -466,6 +497,8 @@
          # Otherwise, rb_gc_call_finalizer_at_exit() can delete
          # stuff that Qt::Application still needs for its cleanup.
          def exec
+            @ruby_threads_timer_id = -1
+
              method_missing(:exec)
              self.dispose
              Qt::Internal.application_terminated = true
@@ -3149,4 +3182,32 @@
      end
  end

+# We're doing some trick here by redefining all the methods for new 
thread creation.
+# Then we adding custom function call to the user's block passed to one 
of these functions.
+class Thread
+    class << self
+        alias :__oldNew :new
+        alias :__oldStart :start
+        alias :__oldFork :fork
+    end
+
+    def self.decorate_thread(old_method, *args, &block)
+        Qt::Application.instance.send :enable_ruby_threads
+        send old_method, *args, &proc{ block.call; 
Qt::Application.instance.send :disable_ruby_threads }
+    end
+    private_class_method(:decorate_thread)
+
+    def self.new(*args, &block)
+        decorate_thread :__oldNew, *args, &block
+    end
+
+    def self.start(*args, &block)
+        decorate_thread :__oldStart, *args, &block
+    end
+
+    def self.fork(*args, &block)
+        decorate_thread :__oldFork, *args, &block
+    end
+end
+
  # kate: space-indent false;



More information about the Kde-bindings mailing list