How to make a GObject singleton

A while back some people asked me to blog about how to make a GObject singleton. I think we are doing it right in Empathy’s code.

The most common way of doing a singleton is to add a function like that:

foo_bar_get_default (void)
  static FooBar *self = NULL;

  if (self == NULL)
    self = foo_bar_new ();

  return self;

It means that you should never unref the return value, and the singleton is leaked for the entire live of the process (unless you play some atexit magic). It also means that g_object_new(FOO_TYPE_BAR, NULL) will return a new object and not a singleton, which is not friendly for bindings.

Here is how we are doing it most of the time in Empathy:

static GObject*
constructor (GType type,
                 guint n_construct_params,
                 GObjectConstructParam *construct_params)
  static GObject *self = NULL;

  if (self == NULL)
      self = G_OBJECT_CLASS (foo_bar_parent_class)->constructor (
          type, n_construct_params, construct_params);
      g_object_add_weak_pointer (self, (gpointer) &self);
      return self;

  return g_object_ref (self);

static void
foo_bar_class_init (FooBarClass *klass)
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->constructor = constructor;

With that code, g_object_new() will return a singleton, and will always return a new ref. That means that you have to call g_object_unref() on the singleton once you don’t need it anymore, just like any normal object. If the last user of the singleton drops its ref, then the object is finalized (so there is no leak) and next time someone needs the singleton, a new one will be created (thanks to the weak pointer).

Of course to avoid object create/destroy ping-pong, you could want to keep a ref for the whole live of the process anyway, it really depend on your needs. But if you are writing a library, you cannot know in advance if the object will be needed for the whole live of the process, so it’s better to let the program using the library decide by managing the refcount itself.

Update: Thanks to Rony and Alexander for pointing me that this is not thread-safe. I think we have to use a mutex in that case. If someone has a better idea, please tell me 🙂

14 thoughts on “How to make a GObject singleton”

  1. I don’t think this is thread-safe. Object construction is not serialized, so concurrent invocations can create two object instances.

    You need to use G_ONCE.

  2. Of course, G_ONCE doesn’t play nicely with the object eventually being finalized and re-created, so perhaps you need a real lock.

  3. In fact, thread safety in the unref situation is quite complex. You can’t just unset the global instance pointer in the finalizer, because some other thread could call g_object_new right before that is NULLed out and revive the object at a time when its not allowed.

    The correct solution is to unset the global instance pointer in dispose (using locks), since its allowed to revive the object from dispose. Of course if some other dispose handler revives the object after NULLing then you can get two live instances. I don’t think that is fixable though, so don’t do that.

  4. @Alexander: Indeed, like most of GLib, it is not thread safe. I didn’t though about that case, tbh. I think there is no solution but using a mutex to make it safe. I leave this as exercise to my readers 😀

  5. Singletons are evil. Just pass the global object along in the function call.

  6. I should note that I don’t hold this GObject singleton idea in high regards. If you call g_object_new(), you want a new object, in particular because g_object_new() allows setting different properties and nowhere in your code is there a check that the user requested the same properties. So I very much prefer the first method you listed with the separate function.

    That said, if you want thread safety and object destruction when the last reference is gone, you can’t bypass a Mutex. Usually for applications it should however not be an issue to retain the object indefinitely and never destruct it. And then GOnce is perfectly fine (as is just constructing it in the init function).

  7. Almosst all glib global state (like a singleton would be) is in fact threadsafe. Only instance-data are not threadsafe.

  8. If the code runs on X11, you can use selection ownership to test if an instance exists. Window managers do this. You can also use that selection to communicate with the first instance, in case it should open a new window or something like that.

Comments are closed.