[ruby-gnome2-doc-cvs] [Ruby-GNOME2 Project Website] update - tips_threads

Zurück zum Archiv-Index

ruby-****@sourc***** ruby-****@sourc*****
2008年 4月 20日 (日) 10:35:43 JST


-------------------------
REMOTE_ADDR = 218.138.133.44
REMOTE_HOST = 
        URL = http://ruby-gnome2.sourceforge.jp/hiki.cgi?tips_threads
-------------------------
@@ -1 +1,64 @@
-Ruby threads and Gtk (avoid seg faults!)
+(This page originally by Tal Liron)
+
+This is a crucial "tip," and in fact qualifies, I believe, as a major warning or fix for using Ruby with the Gtk library.
+
+The warning is this: If you call Gtk methods from outside of Gtk's main thread, there is a chance that the Ruby interpreter (not merely your Ruby application!) will crash with a segmentation fault (seg fault) error, seemingly at random. This is not an exception you can catch. It is fatal and crippling, and very difficult to debug.
+
+You might be using Ruby threads even without knowing! For example, if you receive events or callbacks to your Ruby methods or blocks from another library or service, these calls may very well be occurring on other threads. If that's the case, and you call Gtk from within your callbacks, you risk a seg fault.
+
+Otherwise you might have your own worker thread in the background doing some work, which occasionally needs to call Gtk to update a widget. (Side note: If you are using Ruby threads, be sure to protect your thread-shared resources with either a Monitor or a Mutex! The difference: monitors are safer, in that they are re-entrable from the same thread; mutexes aren't, but perform better.)
+
+First, force all your your Ruby threads to start from within the main loop using the standard Gtk.init method. You can call Gtk.init as many times as necessary. For example:
+
+ Gtk.init_add do
+	DBus.start_listener
+ end
+
+Next, queue your Gtk activities as blocks to be called in Gtk's main thread. The following code helps with this. (Based on Mathieu Blondel's suggestion. [[http://www.ruby-forum.com/topic/125038|See this topic on the Ruby Forum for a discussion.]])
+
+ module Gtk
+	GTK_PENDING_BLOCKS = []
+	GTK_PENDING_BLOCKS_LOCK = Monitor.new
+
+	def Gtk.queue &block
+		if Thread.current == Thread.main
+			block.call
+		else
+			GTK_PENDING_BLOCKS_LOCK.synchronize do
+				GTK_PENDING_BLOCKS << block
+			end
+		end
+	end
+
+	def Gtk.main_with_queue timeout
+		Gtk.timeout_add timeout do
+			GTK_PENDING_BLOCKS_LOCK.synchronize do
+				for block in GTK_PENDING_BLOCKS
+					block.call
+				end
+				GTK_PENDING_BLOCKS.clear
+			end
+			true
+		end
+		Gtk.main
+	end
+ end
+
+Usage is very simple:
+
+Start your Gtk application by calling Gtk.main_with_queue rather than Gtk.main. The "timeout" argument is in milliseconds, and it is the maximum time that can pass until queued blocks get called: 100 should be fine. 
+
+Whenever you need to queue a call, use Gtk.queue. For example:
+
+ def my_event_callback
+	Gtk.queue do
+		@image.pixbuf = Gdk::Pixbuf.new @image_path, width, height
+	end
+ end
+
+Issues:
+
+1. Keep your queued blocks lean. Do all your CPU-intensive work outside of the queued block. This will help keep Gtk responsive.
+2. None yet!
+
+(If you edit this wiki page, please annotate your change clearly!)




ruby-gnome2-cvs メーリングリストの案内
Zurück zum Archiv-Index