Forum: Ruby-Gnome 2 main_iteration in threads lock up the main_thread?

8e6374c0ef7b66942f34798e31edf014?d=identicon&s=25 Dobai-Pataky Bálint (Guest)
on 2007-09-18 16:32
(Received via mailing list)
Attachment: gtk_thread.rb (281 Bytes)
Attachment: dpblnt.vcf (162 Bytes)
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
35f0e7653d7404ac987b0383e1d76e2e?d=identicon&s=25 Martin Portman (Guest)
on 2007-09-19 10:55
(Received via mailing list)
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(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
8e6374c0ef7b66942f34798e31edf014?d=identicon&s=25 Dobai-Pataky Balint (Guest)
on 2007-09-19 18:16
(Received via mailing list)
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.
0158871402c1ecfa57952e8a379cfd10?d=identicon&s=25 Daniel Lucraft (lucraft)
on 2007-09-20 14:48
(Received via mailing list)
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 Balint 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-...
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
8e6374c0ef7b66942f34798e31edf014?d=identicon&s=25 Dobai-Pataky Bálint (Guest)
on 2007-09-20 21:29
(Received via mailing list)
Attachment: dpblnt.vcf (162 Bytes)
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
A7cffc55b637324cde403276be979223?d=identicon&s=25 Nicholas Rahn (Guest)
on 2007-09-21 09:15
(Received via mailing list)
Attachment: InfoBar.rb (4 KB)
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
35f0e7653d7404ac987b0383e1d76e2e?d=identicon&s=25 Martin Portman (Guest)
on 2007-09-21 11:28
(Received via mailing list)
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(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
C838db9af1d90a87a828ecad8556b804?d=identicon&s=25 Guillaume Cottenceau (Guest)
on 2007-09-26 14:48
(Received via mailing list)
On 9/21/07, Martin Portman <martin.portman@iptest.com> 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 Cottenceau - http://zarb.org/~gc/
C838db9af1d90a87a828ecad8556b804?d=identicon&s=25 Guillaume Cottenceau (Guest)
on 2007-10-04 13:22
(Received via mailing list)
On 9/18/07, Dobai-Pataky Bálint <dpblnt@gmail.com> 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...
http://sourceforge.net/mailarchive/message.php?msg...

--
Guillaume Cottenceau - http://zarb.org/~gc/
35f0e7653d7404ac987b0383e1d76e2e?d=identicon&s=25 Martin Portman (Guest)
on 2007-10-09 16:45
(Received via mailing list)
Guillaume Cottenceau 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...
> 
http://sourceforge.net/mailarchive/message.php?msg...
>

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
A2a8b503860ac2fec8b55222fd533e3f?d=identicon&s=25 Loiseleur Michel (Guest)
on 2007-10-09 18:17
(Received via mailing list)
Martin Portman 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 Cottenceau 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,
C838db9af1d90a87a828ecad8556b804?d=identicon&s=25 Guillaume Cottenceau (Guest)
on 2007-10-10 11:34
(Received via mailing list)
> 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 :)

--
Guillaume Cottenceau - http://zarb.org/~gc/
A7cffc55b637324cde403276be979223?d=identicon&s=25 Nicholas Rahn (Guest)
on 2007-10-20 15:02
(Received via mailing list)
Martin Portman 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
8e6374c0ef7b66942f34798e31edf014?d=identicon&s=25 Dobai-Pataky Bálint (Guest)
on 2007-10-20 21:54
(Received via mailing list)
Attachment: dpblnt.vcf (162 Bytes)
Nicholas Rahn wrote:
>>> 
http://sourceforge.net/mailarchive/message.php?msg...
>> 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.
1ba7514948bfec30a29598426c060963?d=identicon&s=25 Mathieu Blondel (Guest)
on 2007-10-28 00:15
(Received via mailing list)
Hi,

I've tested the code that Guillaume Cottenceau 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 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

- 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 Blondel
Ba086c38ee95ba6bba494c5bbb332472?d=identicon&s=25 Boris Kabakov (banderlog)
on 2010-01-20 21:06
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?
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.