Why are GSocket's properties not thread-safe?

Hi,
I would love to use GSocket in my application. I just wonder why its properties are not thread-safe. Is there a common way to modify GSocket’s properties within UI, whereas the GSocket listens in a different thread?

typedef struct _MyData MyData;

struct _MyData
{
  GSocket *socket;
  GSocketAddress *socket_address;
};

gpointer my_socket_listen(MyData *data)
{
  GError *error;

  error = NULL;
  data->socket = g_socket_new (G_SOCKET_FAMILY_IPV4,
    G_SOCKET_TYPE_STREAM,
    0,
    &error);

  data->socket_address = g_inet_socket_address_new_from_string("127.0.0.1",
    10000);

  error = NULL;
  g_socket_bind (data->socket, data->socket_address, FALSE, &error);

  error = NULL;
  g_socket_listen(data->socket, &error);

  g_thread_exit(NULL);
}

int
main(int argc, char **argv)
{
  MyWindow *window;
  GThread *thread;
  MyData *data;

  gtk_init(&argc, &argv);

   window = my_window_new();
  data =
    window->data = g_new(MyData, 1);

  thread = g_thread_new("socket-thread",
    my_socket_listen,
    data);

  /*
   * There is a Gtk dialog allowing to modify MyData's
   * socket and socket_address fields
   */
  gtk_widget_show_all(window);

  gtk_main();

  return(0);
}

Just after some research I found GTask but I think it is not what I want. Since I don’t need an async result but rather pass data to the async function. But is definitely a closer look worth :slight_smile:


by Joël

Unless explicitly stated in its documentation, no object in GLib (or GObject or GIO) is thread-safe. This is because making things thread-safe introduces a large synchronisation overhead which most applications don’t need; i.e. it’s inefficient.

The typical way to send messages between threads is to use g_idle_add() to schedule an idle callback function to be invoked by the GMainContext for the thread you want (in this case, the thread which is running the GSocket). There are some relevant articles here:

I think the first question to answer here, though, is: why is the GSocket in a separate thread?

1 Like

Hi,

No. I don’t need g_idle_add(). I have an existing application doing pthread and doing linux sockets. I would love to make my code more portable and not rewrite its design.

I think, I am fine with doing read() and write() on the file descriptor on the socket from g_socket_accept() in its very own threads.

See g_socket_get_fd(). But, it is obviously that I can’t modify directly the socket. So I make use of my message queue.

I don’t understand what you are suggesting, sorry.

If you want to pass messages between threads, GLib provides g_idle_add() for message passing.

If you want to use a GSocket from another thread, it’s probably best to pass messages from one thread to another to trigger property changes on the socket.

Otherwise, you should be able to safely change GSocket properties from another thread if you use a mutex to lock all calls to the g_socket_*() methods from all threads, but that includes all read calls in your worker thread, which would slow things down considerably due to the locking overhead.

g_idle_add() resides in GMainLoop, I use g_timeout_add() anyway.

But to do messages from GMainLoop to my thread was the question about.

What I need is:

GMainLoop -> GThread

and not

GThread -> GMainLoop

If you are curious what changes I want to accomplish look at my coming changelog:

http://git.savannah.nongnu.org/cgit/gsequencer.git/tree/ChangeLog?h=3.0.x

These are my existing objects involved:

http://git.savannah.nongnu.org/cgit/gsequencer.git/tree/ags/audio/osc/ags_osc_server.c?h=3.0.x
http://git.savannah.nongnu.org/cgit/gsequencer.git/tree/ags/audio/osc/ags_osc_connection.c?h=3.0.x
http://git.savannah.nongnu.org/cgit/gsequencer.git/tree/ags/audio/osc/ags_osc_client.c?h=3.0.x

I am just seeking for inspiration to improve next major release.


by Joël

What you’re asking for is a way to send an interrupt to another thread, which is not generally possible.

In general, to receive a message in a thread, you need to be running a main loop in that thread.

Or writing a dispatcher that polls for messages :wink:

That’s a main loop in all but name. :slight_smile:

It feels somehow wrong to do more than one GMainLoop …
like having main() twice.

But assumed I would create an additional GMainContext, there is no way to use:

  • g_timeout_add()
  • g_idle_add()

cheers, Joël

Just looked at the glib source code, it is true that it is going to use g_main_context_default().

Why isn’t it done by TSD using g_private_set()?

What about to implement following functions:

  • g_timeout_add_with_context()
  • g_idle_add_with_context()

Where you can specify the GMainContext.

You can use g_idle_source_new() and g_timeout_source_new(), and then attach them to your main context. g_idle_add() and g_timeout_add() are simple wrappers for those functions centered around the default main context.

Thank you @ebassi. I am just exploring the asynchronous API and discovered:

  • g_main_context_invoke()

May be I am going to rethink some concepts of my application.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.