In one of my classes, we used Ruby and Gtk, but some issues popped up. The most obvious is using a block to do GUI update stuff and the like, from another thread. Things die. Puppies are killed.
I found this post on Ruby Forum which fixed the problem.
Relevant code.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "thread" | |
module Gtk | |
# Thread-safety stuff. | |
# Loosely based on booh, by Guillaume Cottenceau. | |
PENDING_CALLS_MUTEX = Mutex.new | |
PENDING_CALLS = [] | |
def self.thread_protect(&proc) | |
if Thread.current == Thread.main | |
proc.call | |
else | |
PENDING_CALLS_MUTEX.synchronize do | |
PENDING_CALLS << proc | |
end | |
end | |
end | |
def self.thread_flush | |
if PENDING_CALLS_MUTEX.try_lock | |
for closure in PENDING_CALLS | |
closure.call | |
end | |
PENDING_CALLS.clear | |
PENDING_CALLS_MUTEX.unlock | |
end | |
end | |
def self.init_thread_protect | |
Gtk.timeout_add(100) do | |
PENDING_CALLS_MUTEX.synchronize do | |
for closure in PENDING_CALLS | |
closure.call | |
end | |
PENDING_CALLS.clear | |
end | |
true | |
end | |
end | |
end |
Basically, you call the Gtk.init_thread_protect
method first when you
start things up, then, whenever you need to do GUI update stuff, just
wrap it in a Gtk.thread_protect {}
block. Voila! It works. No more
crashes. In looking at this code again now, some things could be made
more Rubyesque, but we'll go with it.
My version with minor changes:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "thread" | |
module Gtk | |
PENDING_CALLS_MUTEX = Mutex.new | |
PENDING_CALLS = [] | |
def self.thread_protect(&proc) | |
if Thread.current == Thread.main | |
proc.call | |
else | |
PENDING_CALLS_MUTEX.synchronize do | |
PENDING_CALLS << proc | |
end | |
end | |
end | |
def self.thread_flush | |
if PENDING_CALLS_MUTEX.try_lock | |
PENDING_CALLS.each { |closure| closure.call } | |
PENDING_CALLS.clear | |
PENDING_CALLS_MUTEX.unlock | |
end | |
end | |
def self.init_thread_protect | |
Gtk.timeout_add(100) do | |
PENDING_CALLS_MUTEX.synchronize do | |
PENDING_CALLS.each { |closure| closure.call } | |
PENDING_CALLS.clear | |
end | |
true | |
end | |
end | |
end |