Main_iteration in threads lock up the main_thread?


#1

hi,

i don’t know if this is already covered in some docs,
or am i just implementing something wrong.
so i ask you about it.

i attached a script, which hangs it’s Gtk.main_loop (i guess) if you
click it’s button.
while i was simplifying it i ran it for about 5 times detached, and i
locked my gnome up with it.
strange.

a tip to reproduce it: start 2 copies of the script, lock up one, click
on it’s close
and before gtk notices the first script should be killed you hang the
second one.
thus gtk will not be able to update it’s “script1 not respondig
what-to-do” window.

please take a look at it.
thanks in advice

Balint


#2

Dobai-Pataky Bálint wrote:

hi,

i attached a script, which hangs it’s Gtk.main_loop (i guess) if you
click it’s button.
while i was simplifying it i ran it for about 5 times detached, and i
locked my gnome up with it.
strange.

i can recreate the hang running under windows. i do this running two
copies and just dragging the windows around, no button clicking.

but i don’t know why it happens either! i’d speculate that your own
event
processing loop is getting tangled up with the one inside Gtk.main,
but i don’t know how to prove this.

if you told us what you are trying to achieve, maybe we could try to
suggest an alternative way of doing it without the extra loop.

martin


This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft® Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/


#3

im loading a treeview list with data, and i want the progresbar to
appear
only if thel load will be long, this means that after 0.5 sec, update it
every 0.2 sec, and hide it 0.5 secs after loading finished. and since
the
main process is busy gtk won’t give me the timeout by
Gtk::timeout_add(500),
so i decided to run a background thread on that interval (with sleeps)
the
ruby way, and update the progress there when needed. but that appears to
be
hanging too.
currently i update the progress at every 5%, but that’s an ugly
solution. it
appears at 0% and disappears at 100%.
i’d like to use the timeouts or the second thread.

thanks for your kind answer.


#4

That sounds like a job for a thread for sure.

On my linux box I’m getting warnings but no hang.

GLib-WARNING **:g_main_context_prepare(): main loop already active
in another thread

This suggests to me that you shouldn’t be using Gtk.main_iteration_do
while the Gtk.main loop is running. Removing that call gets rid of the
warnings for me and it still works as expected.

Can you explain why you need the call to main_iteration_do, and whether
your code still hangs without it?

Dan

Dobai-Pataky B. wrote:

 > while i was simplifying it i ran it for about 5 times detached,
but i don't know how to prove this.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

https://lists.sourceforge.net/lists/listinfo/ruby-gnome2-devel-en


This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft® Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/


#5

Hi Balint,

I’m attaching a file that I use to manage the progress bar in my Grism
application (http://www.grism.org). Maybe you’ll find some useful ideas
in
it.

In Grism I use it like this:

my_infobar_instance.run( “Doing some long running action…” ) do |ib|
# Do my long running action.
end

NOTE: you can just run this file like ‘ruby InfoBar.rb’ as there is a
little test main program. The test program does seem to crash when you
click stop, but i don’t actually use the stop method in Grism right now
so i haven’t updated the test main program yet.

Let me know if you have any questions. Hope it helps.
Cheers,
Nick


#6

Hi,

I want all the widgets in a container to have the same bg colour.
So I recursively use modify_bg to achieve this:

def set_colour_recursive( wid, col )
wid.modify_bg( Gtk::STATE_NORMAL, col )
if( wid.respond_to? :children )
wid.children.each{|child| set_colour_recursive( child, col ) }
end
end

But this is very slow, as the widget hierarchy can be quite complex
and deep.

Is there a way for a widget to inherit its colour from its container, or
can anyone think of a smarter faster way to do this?

Thanks,
Martin.


This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft® Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/


#7

This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft® Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/


#8

On 9/18/07, Dobai-Pataky Bálint removed_email_address@domain.invalid wrote:

strange.
AFAIK, you cannot trustfully call any ruby-gtk2 API from a ruby thread
other than the main thread. See:

http://sourceforge.net/mailarchive/message.php?msg_id=dc3bf85805070310347dd879d4%40mail.gmail.com
http://sourceforge.net/mailarchive/message.php?msg_id=dc3bf8580611050936s1a7ae9dcpda1501972d953a89%40mail.gmail.com


Guillaume C. - http://zarb.org/~gc/


#9

Guillaume C. wrote:

[snip]

AFAIK, you cannot trustfully call any ruby-gtk2 API from a ruby thread
other than the main thread. See:

http://sourceforge.net/mailarchive/message.php?msg_id=dc3bf85805070310347dd879d4%40mail.gmail.com
http://sourceforge.net/mailarchive/message.php?msg_id=dc3bf8580611050936s1a7ae9dcpda1501972d953a89%40mail.gmail.com

Whoa! This is quite a big issue, right? So I want to clarify it for my
understanding:

If I do stuff like:
button.signal_connect(“clicked”){
other_button.label.set_text( “hello” )
progress_bar.set_value( 50 )
}

that’s ok, as the ruby-gtk calls are being made from the main thread,
which was entered
in the Gtk.main statement.

But if I have: (not exactly the correct syntax!)
button.signal_connect(“clicked”){
condition_variable.signal
}

and elsewhere:
Thread.new{
condition_variable.wait
other_button.label.set_text( “hello” )
progress_bar.set_value( 50 )
}

This could lead to the program going haywire.

So to protect myself, any call to ruby-gtk needs to find its way into
the main thread,
which people have done by putting the calls into proc objects, which get
stored and then
executed by code inside the gtk idle loop.

Have I got this right?
Martin


#10

Martin P. a écrit :

Whoa! This is quite a big issue, right? So I want to clarify it for my understanding:
But if I have: (not exactly the correct syntax!)

This could lead to the program going haywire.

So to protect myself, any call to ruby-gtk needs to find its way into the main thread,
which people have done by putting the calls into proc objects, which get stored and then
executed by code inside the gtk idle loop.

Have I got this right?

That’s my understanding too. And it seems it’s implemented with this
spirit in perl.
That’s why on the last post about “Main loop busier than expected”, I
was quite surprised with this :

Guillaume C. has written :

This is to not break support for ruby multi-threading. Choice was to
not block forever waiting for Gtk events in the Gtk mainloop, else
ruby threads won’t have any chance to be scheduled. I am not sure
about the other possible design choices, but as long as you want to
handle more than one event loop, you bump into polling because the
event loops won’t be able to cooperate at the syscall level. It would
be interesting to compare with the approach of Gtk2-Perl and pygtk,
but I don’t know them.

Is this not the time to really block in gtk main loop, now that is
more clear why perl-gtk do that ?
I cannot see any sane reason to keep a possibility of corruption. And
this does not interfere with the possibility of using threads, anyway.
They could be “launched” with glib “timeout_add” method, for instance.

Regards,


#11

On 9/21/07, Martin P. removed_email_address@domain.invalid wrote:

end

But this is very slow, as the widget hierarchy can be quite complex
and deep.

I’m surprised this is slow. This might be due to too much refreshing
(does it flicker?). You may try to #hide_all the toplevel widget,
perform the modification, then #show_all.

Or maybe, if the hierarchy is very, very complex, this might be due to
ruby<->gtk overhead (I had a similar problem for manually drawing a
recurrent small image on the border of a larger image, I had to write
the drawing loop in a C extension to obtain reasonable speed).


Guillaume C. - http://zarb.org/~gc/


#12

Nicholas R. wrote:

http://sourceforge.net/mailarchive/message.php?msg_id=dc3bf8580611050936s1a7ae9dcpda1501972d953a89%40mail.gmail.com
that’s ok, as the ruby-gtk calls are being made from the main thread, which was entered
other_button.label.set_text( “hello” )

Alternatively, you could say this:

Gtk.idle_remove( id )

false
}

Hope this helps.
Nick

nop,
since the cpu has a heavy computation, Gtk won’t give it an idle hook.


#13

Whoa! This is quite a big issue, right?

At least, it bothered me quite a bit and I went that far to try to
understand the root of the problem, and find a solution. Since then,
I’m not aware of particular changes.

}

This could lead to the program going haywire.

Yes. As this is related to threading, the problems are not
reproduceable, and you might never see any problems, especially if
your program performs no CPU-intensive tasks (which is often the case
for GUI programs).

So to protect myself, any call to ruby-gtk needs to find its way into the main thread,
which people have done by putting the calls into proc objects, which get stored and then
executed by code inside the gtk idle loop.

At least, that’s one possible solution to the problem :slight_smile:


Guillaume C. - http://zarb.org/~gc/


#14

Hi,

I’ve tested the code that Guillaume C. is using in booh to do
GUI stuff from within Ruby threads, in Fantasdic. I can report it to
work well and it seems to have fixed “random” crashes that I was
experiencing. Here’s how I included it in my application:

require “thread”

module Gtk
# Thread-safety stuff.
# Loosely based on booh, by Guillaume C…

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

  • I call Gtk.init_thread_protect once when I initialize my GUI stuff
  • Every time I need to update my GUI from withing a thread, I do:
    Gtk.thread_protect do { … }
  • I call Gtk.thread_flush right after killing a thread when I ever
    happen to need kill a thread

HTH,

Mathieu B.


#15

good day,
I think that I just missing something, but, when i try to run simple
script:

#!/usr/bin/ruby
require ‘gtk2’
require ‘monitor’
require ‘thread’

##########################################################

this part from

http://ruby-gnome2.sourceforge.jp/hiki.cgi?tips_threads

##########################################################
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

###########################################

My part

###########################################
$icon = Gtk::StatusIcon.new
$icon.stock=Gtk::Stock::YES
$icon.blinking = true

Gtk.queue {
loop {
sleep 1
b=File.read(‘unread_tmp’).to_i
if b == 0 #&& $icon.visible?
$icon.visible=false
elsif b > 0 # && $icon.visible? == false
$icon.visible=true
else
sleep 1
end
sleep 1
puts b
}
}

Gtk.main_with_queue 100


I can achieve only 2 results - loop working, Gtk.main_with_queue 100 not
starting, or I am use Thread.new for loop or Gtk.main and it eats all my
CPU

How I can control icon.visible from loop?


#16

Martin P. wrote:

Whoa! This is quite a big issue, right? So I want to clarify it for my understanding:
But if I have: (not exactly the correct syntax!)

This could lead to the program going haywire.

So to protect myself, any call to ruby-gtk needs to find its way into the main thread,
which people have done by putting the calls into proc objects, which get stored and then
executed by code inside the gtk idle loop.

You can also insert code into the GTK main loop from another thread like
this:

  id = Gtk.idle_add() {

Execute some ruby-gtk stuff.

Return ‘false’ so that this block will no longer be executed.

If you don’t explicitly say ‘false’ here, this proc will be

    # executed over and over.

Alternatively, you could say this:

Gtk.idle_remove( id )

false
}

Hope this helps.
Nick