views:

3140

answers:

4

Hello, I want to create a singleton in C. What's the best way?

A concurrent solution would be nice..

Edit - I am aware that C isn't the first langague you would use for a Singleton, If it was the question was much simpler.

+17  A: 

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:

 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.

dirkgently
Thanks, Just checking - This solution isn't adapted to multi-threaded environments, right?
Liran Orevi
This way of initializing is safe in a multi-threaded environment when there is no other dependency of the singleton instance on any other static present within the program.(IIRC, there is some ambiguity w.r.t initialization order of statics which is why Gamma et al left this out of their C++ implementation.) The downside is you can only use a constant expression. A double-checked locking based singleton for multi-threaded environment will need a thread library for mutexes etc.
dirkgently
C is more than suitable for OOP. in fact, the only features of C++ that really help OOP are syntactic sugar.
Javier
Let's start with polymorphism in C?
dirkgently
I am not denying that this can be done, but not without spending an inordinate amount of time and effort. E.g: hacking up polymorphic functions using macros is one way to go -- but you lose type safety. There is no RTTI in C either. (And yes, C does have limited polymorphism, think of the operators +, - etc.)
dirkgently
+4  A: 

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());
Michael
+1 Nice pattern - although this technique does assume you are allowed to call CreateNewObj more than once. Depending on the particulars of the resources being handled by the singleton, you may not have that luxury.
Eclipse
True, if that's not possible you need to use a heavier solution, like a lock.
Michael
On a sytem with pthreads, one can use pthread_once() to run the initialization code only once.
Blair Zajac
Vista added IninitOnceExecuteOnce as well, but that eliminates XP or 2k3.
Michael
+13  A: 

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

Adam Jaskiewicz
I understand the way a global can be used, but the fact that C++ also have global variables, and that on C++ the singleton implementation is usually not with global, makes me aspire for more..
Liran Orevi
C++ is an object-oriented language; C is not. Sure, you *can* do OOP in C, but it's ugly, hacky, and a pain to deal with. Similarly, you *can* write almost-C in C++, but then why are you using C++? So really, just use a global. There's no sense trying to disguise what you're doing by obfuscating it with a bunch of function-local static variables and pre-processor macros.
Adam Jaskiewicz
+5  A: 

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.

justinhj