Re: Emitting signals from threads

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

 



Thanks for the reply.

When calling g_main_context_invoke_full(), I am using NULL as the
context pointer. According to the documentation of
g_main_context_invoke():

        "If context is NULL then the global default main context — as
returned by g_main_context_default() — is used."

So, the code should be using the correct context.

One of the main reasons why I am not using g_idle_add() is the timing
of the callback. I don't want to defer the processing of the callback
to the "idle" time since this is signal handling related. Another
advantage of g_main_context_invoke[_full]() is that it will check the
"context" of the caller and, if possible, will call the callback
directly:

       "If context is owned by the current thread, function is called
directly. Otherwise, if context is the thread-default main context of
the current thread and g_main_context_acquire()
       succeeds, then function is called and g_main_context_release()
is called afterwards.
       In any other case, an idle source is created to call function
and that source is attached to context (presumably to be run in
another thread). The idle source is attached with
       G_PRIORITY_DEFAULT priority. If you want a different priority,
use g_main_context_invoke_full()."

Your suggested implementation is basically the GLib's async queues.
Or, may be, a custom event source. However, it seems that
g_main_context_invoke_full() should be doing exactly that. With all
due respect, I also don't see how it would solve the issue. If the
current implementation has an problem with locking/race conditions,
would your suggested implementation suffer from the same issue since
it's using the same or similar mechanism for calling the callback?

Thank you,

Mitko


On Mon, Jan 7, 2019 at 3:54 PM ente <ente@xxxxxxx> wrote:
>
> 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