Question

What's the best way to create a singleton in C? A concurrent solution would be nice.

I am aware that C isn't the first language you would use for a singleton.

Was it helpful?

Solution

First, C is not suitable for OO programming. You'd be fighting all the way if you do. Secondly, singletons are just static variables with some encapsulation. So you can use a static global variable. However, global variables typically have far too many ills associated with them. You could otherwise use a function local static variable, like this:

 int *SingletonInt() {
     static int instance = 42;
     return &instance;
 }

or a smarter macro:

#define SINGLETON(t, inst, init) t* Singleton_##t() { \
                 static t inst = init;               \
                 return &inst;                       \
                }

#include <stdio.h>  

/* actual definition */
SINGLETON(float, finst, 4.2);

int main() {
    printf("%f\n", *(Singleton_float()));
    return 0;
}

And finally, remember, that singletons are mostly abused. It is difficult to get them right, especially under multi-threaded environments...

OTHER TIPS

You don't need to. C already has global variables, so you don't need a work-around to simulate them.

It's the same as the C++ version pretty much. Just have a function that returns an instance pointer. It can be a static variable inside the function. Wrap the function body with a critical section or pthread mutex, depending on platform.

#include <stdlib.h>

struct A
{
    int a;
    int b;
};

struct A* getObject()
{
    static struct A *instance = NULL;

    // do lock here
    if(instance == NULL)
    {
        instance = malloc(sizeof(*instance));
        instance->a = 1;
        instance->b = 2;
    }
    // do unlock

    return instance;
};

Note that you'd need a function to free up the singleton too. Especially if it grabs any system resources that aren't automatically released on process exit.

EDIT: My answer presumes the singleton you are creating is somewhat complex and has a multi-step creation process. If it's just static data, go with a global like others have suggested.

A singleton in C will be very weird . . . I've never seen an example of "object oriented C" that looked particularly elegant. If possible, consider using C++. C++ allows you to pick and choose which features you want to use, and many people just use it as a "better C".

Below is a pretty typical pattern for lock-free one-time initialization. The InterlockCompareExchangePtr atomically swaps in the new value if the previous is null. This protects if multiple threads try to create the singleton at the same time, only one will win. The others will delete their newly created object.

MyObj* g_singleton; // MyObj is some struct.

MyObj* GetMyObj()
{
    MyObj* singleton;
    if (g_singleton == NULL)
    {
        singleton = CreateNewObj();

        // Only swap if the existing value is null.  If not on Windows,
        // use whatever compare and swap your platform provides.
        if (InterlockCompareExchangePtr(&g_singleton, singleton, NULL) != NULL)
        {
              DeleteObj(singleton);
        }
    }

    return g_singleton;
}

DoSomethingWithSingleton(GetMyObj());

Here's another perspective: every file in a C program is effectively a singleton class that is auto instantiated at runtime and cannot be subclassed.

  • Global static variables are your private class members.
  • Global non static are public (just declare them using extern in some header file).
  • Static functions are private methods
  • Non-static functions are the public ones.

Give everything a proper prefix and now you can use my_singleton_method() in lieu of my_singleton.method().

If your singleton is complex you can write a generate_singleton() method to initialize it before use, but then you need to make sure all the other public methods check if it was called and error out if not.

Just do

void * getSingleTon() {
    static Class object = (Class *)malloc( sizeof( Class ) );
    return &object;
}

which works in a concurrent environment too.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top