Re: Emitting signals from threads

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,


I am not sure with my answer. Treat it as unreliable.

There seems to be a difference between g_idle_add
and g_main_context_invoke_full. While the documentation of idle_add
says:
"Adds a function to be called [...] to the default main loop." (i.e.
main thread / the only gtk-thread) g_main_context_invoke_full does not
mention the main loop - although it mentions a "context" which I have
no experience with and which may be related to the main loop. So maybe
you must retrieve the correct context using g_main_context_default or
g_main_context_acquire. Keep in mind: glib is thread safe, gtk is not.
g_main_context_invoke_full may support glib multi threading while
g_idle_add clearly sends your function call to the gtk thread.

The effect you are describing makes sense to me. The effects you
observe sound very much like race conditions in the treeview event
handler.

Why aren't you using g_idle_add in the first place? In my experience
this works like a charm. Be careful with one thing tho: The main loop
has a "todo-list". Each time you call "g_idle_add" it adds an item to
that todo-list and schedules a call to your function. If your function
doesn't return false, it won't even be taken down from the todo-list.
Each click event ends on that todo-list. Each column resize adds
multiple items to that todo-list (depending on your column resize
policy and the number of rows). As soon as you add more items to that
list, your UI becomes unresponsive. It seems advisable to build your
own shadow todo-list for the update process, i.e.:
* setup a function "update_progress"
* on the first threaded update event, call idle_add for the function
and put the new progress and the row number in your own data structure
* while the function is still "planned in for idle_add", just add new
events to your own data structure
* process 1 to 10 (maybe some more) events on each of the calls
* the function returns true as long as there is still some events in
your own list; it returns false otherwise
* apply mutex checks on your data structure (not sure if i should
mention, I am sure you had this in your mind already)

Each time you update a progress bar in your treeview, several (at least
one) events are added to the gtk-todo list (repaint!, re-order? and
maybe some more). Doing multiple progress events at once may lower the
amount of events, gtk has to process (a re-order affects all rows -
doing an update on multiple rows does not change anything here).

That's my 5 cents. I hope it helped a bit.


regards,


ente


On Mon, 2019-01-07 at 08:28 -0800, Mitko Haralanov via gtk-list wrote:
> Anyone have any ideas? I still can't figure out why the column sizes
> go to
> 0.
> 
> Thank you.
> 
> On Tue, Dec 18, 2018, 13:40 Mitko Haralanov <
> voidtrance@xxxxxxxxx
>  wrote:
> 
> > This is Gtk3:
> > gtk3-3.22.26-2.fc27.x86_64
> > 
> > On Tue, Dec 18, 2018 at 1:14 PM Luca Bacci via gtk-list <
> > gtk-list@xxxxxxxxx
> > > wrote:
> > 
> > > Is it Gtk2 or Gtk3, which version exactly?
> > > 
> > > 
> > > Il giorno mar 18 dic 2018 alle ore 18:47 Mitko Haralanov via gtk-
> > > list <
> > > gtk-list@xxxxxxxxx
> > > > ha scritto:
> > > 
> > > > I mistakenly replied only to Luca!! Forwarding to the list.
> > > > 
> > > > (Sorry, Luca, my bad)
> > > > - Mitko
> > > > 
> > > > ---------- Forwarded message ---------
> > > > From: Mitko Haralanov <
> > > > voidtrance@xxxxxxxxx
> > > > >
> > > > Date: Tue, Dec 18, 2018 at 9:37 AM
> > > > Subject: Re: Emitting signals from threads
> > > > To: Luca Bacci <
> > > > luca.bacci982@xxxxxxxxx
> > > > >
> > > > 
> > > > 
> > > > I found something that is different between the two cases -
> > > > button click
> > > > with signals and without.
> > > > 
> > > > Using the code from the link that Luca posted, I decided to
> > > > print the
> > > > size of each column when a button press is received. As it
> > > > turns out, the
> > > > width of the columns is different in the two cases:
> > > > 
> > > > Without thread signals:
> > > > column[0](193) = 0 -> 193
> > > > cell[0] = min->109, natural->109
> > > > column[1](66) = 193 -> 259
> > > > cell[0] = min->20, natural->20
> > > > cell[1] = min->16, natural->16
> > > > cell[2] = min->35, natural->35
> > > > column[2](36) = 259 -> 295
> > > > cell[0] = min->16, natural->16
> > > > x = 105.872116, y = 259.547516
> > > > 
> > > > (x and y are the coordinates of the button press event)
> > > > 
> > > > With thread signals:
> > > > column[0](0) = 0 -> 0
> > > > cell[0] = min->135, natural->135
> > > > column[1](66) = 0 -> 66
> > > > cell[0] = min->20, natural->20
> > > > cell[1] = min->16, natural->16
> > > > cell[2] = min->35, natural->35
> > > > column[2](36) = 66 -> 102
> > > > cell[0] = min->16, natural->16
> > > > x = 113.528488, y = 158.563782
> > > > 
> > > > As you can see, the width of the first column is 0 when the
> > > > signals are
> > > > being emitted. As expected, if I were to click very close to
> > > > the left
> > > > border of the widget, the edit dialog does not get triggered as
> > > > the x
> > > > coordinate falls within column 1:
> > > > 
> > > > column[0](0) = 0 -> 0
> > > > cell[0] = min->135, natural->135
> > > > column[1](66) = 0 -> 66
> > > > cell[0] = min->20, natural->20
> > > > cell[1] = min->16, natural->16
> > > > cell[2] = min->35, natural->35
> > > > column[2](36) = 66 -> 102
> > > > cell[0] = min->16, natural->16
> > > > x = 21.247330, y = 181.310333
> > > > 
> > > > I could use the cell renderer width if the column width is 0
> > > > but that
> > > > seems unreliable since the cell renderer width is not the same
> > > > as the
> > > > column and it's also not static.
> > > > 
> > > > On Tue, Dec 18, 2018 at 8:23 AM Mitko Haralanov <
> > > > voidtrance@xxxxxxxxx
> > > > >
> > > > wrote:
> > > > 
> > > > > I am not posting the complete function because there is a lot
> > > > > of
> > > > > irrelevant code. I am also not interested in the specific
> > > > > cell renderer but
> > > > > rather the row on which the click occurred.
> > > > > 
> > > > > tatic gboolean on_button_press_event(GtkWidget *widget,
> > > > >       GdkEvent *event,
> > > > >       gpointer data)
> > > > > {
> > > > > GtkTreeView *treeview = GTK_TREE_VIEW(widget);
> > > > > GdkEventButton *button = (GdkEventButton *)event;
> > > > > GtkTreeModel *model;
> > > > > GtkTreePath *path;
> > > > > GtkTreeIter iter;
> > > > > GtkTreeViewColumn *column;
> > > > > GtkScopeProjectEditDialog *dialog;
> > > > > GtkScopeProjectEditData *pdata, fill;
> > > > > GtkScopeProject *project;
> > > > > guint response, index;
> > > > > gboolean ret = FALSE;
> > > > > 
> > > > > if (button->type != GDK_BUTTON_PRESS ||
> > > > >     !gtk_tree_view_get_path_at_pos(treeview, button->x,
> > > > > button->y,
> > > > >    &path, &column, NULL, NULL))
> > > > > return FALSE;
> > > > > 
> > > > > index = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(column),
> > > > > "index"));
> > > > > if (index != TREEVIEW_COLUMN_EDIT)
> > > > > goto done;
> > > > > model = gtk_tree_view_get_model(treeview);
> > > > > if (!gtk_tree_model_get_iter(model, &iter, path))
> > > > > goto done;
> > > > > gtk_tree_model_get(model, &iter, PROJECT_COLUMN_OBJ,
> > > > > &project, -1);
> > > > >         ...
> > > > > 
> > > > > The issue is that the column which is returned by
> > > > > gtk_tree_view_get_path_at_pos() is different depending on
> > > > > whether thread
> > > > > signals are being emitted vs not. I have verified that the
> > > > > button press
> > > > > coordinates are the same (button->x and button->y have the
> > > > > same values in
> > > > > both cases).
> > > > > 
> > > > > 
> > > > > On Tue, Dec 18, 2018 at 5:24 AM Luca Bacci <
> > > > > luca.bacci982@xxxxxxxxx
> > > > > >
> > > > > wrote:
> > > > > 
> > > > > > Hi Mitko! Can you post here the code for the button-press
> > > > > > event
> > > > > > handler?
> > > > > > It should more or less follow the code here:
> > > > > > http://scentric.net/tutorial/sec-misc-get-renderer-from-click.html
> > > > > > 
> > > > > > 
> > > > > > Luca
> > > > > > 
> > > > > > Il giorno lun 17 dic 2018 alle ore 20:28 Mitko Haralanov
> > > > > > via gtk-list <
> > > > > > gtk-list@xxxxxxxxx
> > > > > > > ha scritto:
> > > > > > 
> > > > > > > Hi,
> > > > > > > 
> > > > > > > In my application, I want to be able to update a treeview
> > > > > > > from a
> > > > > > > separate thread. Each treeview row was a column that is a
> > > > > > > progress bar. The
> > > > > > > progress to be displayed is generated by a separate
> > > > > > > thread as to not block
> > > > > > > the UI.
> > > > > > > 
> > > > > > > Since GTK is not thread-safe, the way the application is
> > > > > > > written is
> > > > > > > that the thread, when it needs to emit a signal, will
> > > > > > > prepare the signal
> > > > > > > data and then call g_main_context_invoke_full(NULL, cb,
> > > > > > > data, ...) in order
> > > > > > > to be able to call g_singal_emit() in the global default
> > > > > > > context thread.
> > > > > > > The signal handler updates the tree model, which in turn
> > > > > > > updates the tree
> > > > > > > view.
> > > > > > > 
> > > > > > > For the most part this works with one big, ugly exception
> > > > > > > - the same
> > > > > > > treeview has a column, which is supposed to open the
> > > > > > > item's Edit dialog
> > > > > > > when clicked. So, naturally, I have a button-press
> > > > > > > handler connected to the
> > > > > > > treeview, which launches the Edit dialog when the button
> > > > > > > press occurs in
> > > > > > > the correct column.
> > > > > > > 
> > > > > > > However, when an update is running and the thread is
> > > > > > > continuously
> > > > > > > emitting signals, clicking on *any* column of *any* of
> > > > > > > the other items
> > > > > > > opens the Edit dialog. The treeview behaves as if the
> > > > > > > items in it have only
> > > > > > > one column.
> > > > > > > 
> > > > > > > Every example or document that I have seen in relation to
> > > > > > > signals
> > > > > > > from threads says to emit the signal from a g_idle_add()
> > > > > > > handler. However,
> > > > > > > g_main_context_invoke_full(NULL, ...) should be the same
> > > > > > > as calling
> > > > > > > g_idle_add().
> > > > > > > 
> > > > > > > Can someone shed some light into what might be happening?
> > > > > > > 
> > > > > > > Thank you.
> > > > > > > 
> > > > > > > 
> > > > > > > _______________________________________________
> > > > > > > gtk-list mailing list
> > > > > > > gtk-list@xxxxxxxxx
> > > > > > > 
> > > > > > > https://mail.gnome.org/mailman/listinfo/gtk-list
> > > > > > > 
> > > > > > > 
> > > > > > 
> > > > > > _______________________________________________
> > > > 
> > > > gtk-list mailing list
> > > > gtk-list@xxxxxxxxx
> > > > 
> > > > https://mail.gnome.org/mailman/listinfo/gtk-list
> > > > 
> > > > 
> > > 
> > > _______________________________________________
> > > gtk-list mailing list
> > > gtk-list@xxxxxxxxx
> > > 
> > > https://mail.gnome.org/mailman/listinfo/gtk-list
> > > 
> > > 
> 
> _______________________________________________
> gtk-list mailing list
> gtk-list@xxxxxxxxx
> 
> https://mail.gnome.org/mailman/listinfo/gtk-list
> 



_______________________________________________
gtk-list mailing list
gtk-list@xxxxxxxxx
https://mail.gnome.org/mailman/listinfo/gtk-list



[Index of Archives]     [Touch Screen Library]     [GIMP Users]     [Gnome]     [KDE]     [Yosemite News]     [Steve's Art]

  Powered by Linux