Web lists-archives.com

Re: Emitting signals from threads




Hi Mitko,
last time I tried creating a simple C application for testing but I did get always correct values. (Btw I used g_idle_add)
Can you try to write a minimal test application that still exhibits the problem? That would be very helpful!

Il giorno mer 9 gen 2019, 18:32 Mitko Haralanov via gtk-list <gtk-list@xxxxxxxxx> ha scritto:
After some offline discussion, I decided to experiment with
g_idle_add_full() since that function seems to work for other people.

Unfortunately, it doesn't in my case. The width of the first column is
still 0 and bad behavior is reproducible:

column[0](0) = 0 -> 0
    cell[0] = min->102, natural->102, text->98
column[1](66) = 98 -> 164
    cell[0] = min->20, natural->20
    cell[1] = min->16, natural->16
    cell[2] = min->35, natural->35
column[2](36) = 164 -> 200
    cell[0] = min->16, natural->16
x = 138.000000, y = 274.000000

Looking at the code for g_main_context_invoke_full() and
g_idle_add_full(), as expected, the portion of
g_main_context_invoke_full() that deals with the idle source is
virtually identical to g_idle_add_full(). So, the issue is somewhere
deeper.

Are there any GLib or Gtk+ developers on this list that can offer any help?

On Tue, Jan 8, 2019 at 4:35 PM Lex Trotman <elextr@xxxxxxxxx> wrote:
>
> "calling gtk functions from a thread would be possible only through
> g_idle_add()." thats my understanding from
> https://developer.gnome.org/gdk3/stable/gdk3-Threads.html and thats
> what our app does.  It never seems to be a  performance problem, the
> main thread continuously chews its way through the idle queue.
>
> Cheers
> Lex
>
> On Wed, 9 Jan 2019 at 10:17, Mitko Haralanov <voidtrance@xxxxxxxxx> wrote:
> >
> > I havent looked at the actual code but I am willing to bet that the "idle source" is just using g_idle_add(). If so, g_main_context_invoke_full() is essentially the same.
> >
> > If not the case, calling gtk functions from a thread would be possible only through g_idle_add(). I would think that if that were the case, it would have been mentioned in the docs.
> >
> > Thank you,
> > Mitko
> >
> > On Tue, Jan 8, 2019, 16:11 Lex Trotman <elextr@xxxxxxxxx wrote:
> >>
> >> Hi Mitko,
> >>
> >> Same problem, from g_main_context_invoke() "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)."
> >>
> >> Cheers
> >> Lex
> >>
> >> On Wed, 9 Jan 2019 at 09:55, Mitko Haralanov <voidtrance@xxxxxxxxx> wrote:
> >> >
> >> > Hi Lex,
> >> >
> >> > That is for the "notify" callback, which only deals with free/release
> >> > of the "data" pointer. The "function" callback is different and should
> >> > be called from the context default thread (as the documentation
> >> > describes.)
> >> >
> >> > Thank you,
> >> > Mitko
> >> >
> >> > On Tue, Jan 8, 2019 at 3:44 PM Lex Trotman <elextr@xxxxxxxxx> wrote:
> >> > >
> >> > > Mito,
> >> > >
> >> > > It seems to me that since the g_main_context_invoke_full() docs say
> >> > > "notify should not assume that it is called from any particular
> >> > > thread" that notify cannot call GTK functions since GTK is not thread
> >> > > safe.
> >> > >
> >> > > Cheers
> >> > > Lex
> >> > >
> >> > > PS I'm not on gtk-list and am not gonna join for one line, feel free to forward
> >> > >
> >> > > On Wed, 9 Jan 2019 at 04:03, Mitko Haralanov via gtk-list
> >> > > <gtk-list@xxxxxxxxx> wrote:
> >> > > >
> >> > > > 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
_______________________________________________
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