I've got a script that launches one thread to show a gui progress bar while another thread sends some files. The gui thread will hang, in a bad way, with: /home/roberto/Código/enviado_de_web/lib/gui.rb: line 42 Gtk-CRITICAL **:gtk_main_quit: assertion `main_loops != NULL' failed I say "in a bad way" because the thread for the gui does not die on Ctl-C -- not even if I specifically trap the SIGINT and do the Gtk.main_quit from there. -- it zombies on my system and I have to hunt down the thread and kill -9 it: [506] roberto@quad-g5: ~/Código/enviado_de_web [8:03am]$ ps aux|grep ruby roberto 17949 7.4 0.9 139852 39388 pts/0 Sl 08:03 0:01 ruby ./plugin foobar ? roberto 17977 0.0 0.0 3608 936 pts/0 S+ 08:03 0:00 grep ruby [507] roberto@quad-g5: ~/Código/enviado_de_web [8:03am]$ kill -9 17949 my project is only a couple hundred lines of code, available on git: http://github.com/robbiemu/Enviado-de-web obviously still in an unusable state :)
on 2010-05-16 14:11
on 2010-05-16 15:40
Hmmm... I'm a little bit confused by your code. I don't see a
Gtk.init or Gtk.main anywhere. I probably just missed it.
Your threads look a little confusing to me too. You've got
a thread sitting there doing Gtk.main_iteration forever
with no way to exit.
I admit that I avoid threads altogether unless I have no
choice. But I think I've beaten that dead horse enough ;-)
Here are some thoughts:
I think putting your GTK code in a new thread itself is
probably a bad idea. I suspect it should work, but the
threading code in ruby is different than the threads used
by GTK. Sometimes there are problems. If you want to
use threads with GTK you should stick to simple
implementations.
I also seem to remember that GTK calls *must* be in
the same thread that GTK is started from. This means
that you have to be a bit careful anyway. A much, much
simpler way to do what you want is to run your network
code in a separate thread and have a Gtk.on_idle
function update your progress bar.
But honestly, even that is complicated, since you probably
want to control your app from the gui. Properly syncronizing
your threads so that you don't accidently call GTK code from
a non-GTK thread is a pain in the butt. A much, much, much
simpler approach is to avoid using threads altogether.
If you are sending long files, write a method that simply sends
a few hundred bytes (or whatever you want). When you
want to send your file, add the method to Gtk.on_idle.
When the file is finished, remove it from on_idle. Then you
can update the gtk status directly from your file sending method
if you like. Especially if you use non-blocking writes, your
UI will be insanely responsive at all times too.
Wait... I promised not to beat the dead horse... ;-)
MikeC
on 2010-05-16 16:13
Mike Charlton wrote: > Hmmm... I'm a little bit confused by your code. I don't see a > Gtk.init or Gtk.main anywhere. I probably just missed it. > Your threads look a little confusing to me too. You've got > a thread sitting there doing Gtk.main_iteration forever > with no way to exit. (reading the rest of your message still) Can I call Gtk.init? I thought that all happened behind the scenes. Gtk.main_iteration is supposed to be the same as 1 pass in Gtk.main .. so wrapping it in an appropriate while loop is equivalent to running Gtk.main -- but this way I get to send updates to my progress bar while they happen, instead of all at once at the beginning/end. -- or that's not right?
on 2010-05-16 16:43
Mike Charlton wrote: > I admit that I avoid threads altogether unless I have no > choice. with the average processor today presenting an apparent 8 cores, that's no longer a sustainable way to code, I'm afraid. :) > I think putting your GTK code in a new thread itself is > probably a bad idea. I suspect it should work, but the > threading code in ruby is different than the threads used > by GTK. Sometimes there are problems. If you want to > use threads with GTK you should stick to simple > implementations. This is about as simple as it gets man :) -- did you read the gui code? > I also seem to remember that GTK calls *must* be in > the same thread that GTK is started from. that is interesting. is that "started" the Gtk.init that comes with require "gtk2" ? Or is it the Gtk.main -- they're actually different threads here. Why isn't that in the ruby-gnome2 api docs? I hate it when a specification creates several equivalent ways of doing something, only one of which actually work. :P This whole section in my code, will be refactored out to the gui.rb lib and run entirely in that thread later, but that's once I build a readline version of the progress bar and need to offer the user the option of using that. The idea of using a thread for this came from the fact that I don't know how the plugins will work. so its best to let them update based on the ruby thread scheduler rather than forcing the plugin programmers to impliment their own schedule. especially when the gui will be abstracted out as other guis are added in optionally later. This means > that you have to be a bit careful anyway. A much, much > simpler way to do what you want is to run your network > code in a separate thread and have a Gtk.on_idle > function update your progress bar. Gtk.on_idle is missing from the ruby gnome 2 api documentation :S lol, can you up an example please? > But honestly, even that is complicated, since you probably > want to control your app from the gui. I don't. I literally only need a progress bar. I dont even need a main window. > If you are sending long files, write a method that simply sends > a few hundred bytes (or whatever you want). It would be fast but then I would be responsible for all the plugins and the system wouldnt be externally extensible. > Wait... I promised not to beat the dead horse... ;-) > > MikeC thanks Mike
on 2010-05-16 18:09
On 16 May 2010 23:43, Roberto Cm <ruby-forum-incoming@andreas-s.net> wrote: > one of which actually work. :P I'm not the author of GTK or ruby-gtk. I'm just trying to help you with your problem. Actually, looking at the documentation it seems that you are correct in your assumption that init() does not need to be called. it gets called when you include gtk2.rb http://ruby-gnome2.sourceforge.jp/hiki.cgi?Gtk#Gtk.init My guess is that you need to do your calls to gtk in the same thread that Gtk.init happens in (i.e. where you included gtk2.rb) This may be one of the sources of your problems. The problem as I remember is that GTK has some threads running in it and they are incompatible with ruby threads. There has been discussion about this topic in the past, perhaps others can shed more light on it. It is entirely possible that I have misremembered. I do know that I have had problems in the past updating progress bars from other threads. > Gtk.on_idle is missing from the ruby gnome 2 api documentation :S lol, > can you up an example please? Sorry. Gtk.idle_add() and Gtk.idle_remove(). I'm a bit sleepy tonight... Now that I understand what you are trying to do, replacing your loop with gtk.idle_add do if fase != oldfase g.pulsar(fase) oldfase = fase end end gtk.main might at least get rid of the warning message. Possibly moving the require gtk2 into the thread may help. At the very least your code should quit when you catch the sigint since gtk.quit will stop the main loop. But it occurs to me that if you aren't interested in writing a gui, but are only using the progress bar, perhaps you don't need a main loop in the UI at all. Instead of a float that you are constantly monitoring, you can have a progress object. You run a method on the progress object that increments the value and runs Gtk.main_iteration_do(false) to update the UI (no need to check for events, just don't block). It will cut down on the number of threads anyway... ;-) MikeC
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.