29

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.

nbro
  • 15,395
  • 32
  • 113
  • 196
Liran Orevi
  • 4,755
  • 7
  • 47
  • 64

7 Answers7

36

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...

dirkgently
  • 108,024
  • 16
  • 131
  • 187
  • Thanks, Just checking - This solution isn't adapted to multi-threaded environments, right? – Liran Orevi Apr 29 '09 at 19:00
  • 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 Apr 29 '09 at 19:14
  • 6
    C is more than suitable for OOP. in fact, the only features of C++ that really help OOP are syntactic sugar. – Javier Apr 29 '09 at 19:19
  • Let's start with polymorphism in C? – dirkgently Apr 29 '09 at 19:23
  • 2
    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 Apr 29 '09 at 19:26
  • Since I saw this code I'm trying to do this with a struct. Have you a code sample to show me how to do this? – Leandro Lima Apr 12 '13 at 02:12
  • Can you explain why the macro is "smarter"? And what do you think about this solution ? http://stackoverflow.com/a/5171844/1763602 – Marco Sulla Aug 26 '16 at 18:05
20

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

Adam Jaskiewicz
  • 10,934
  • 3
  • 34
  • 37
  • 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 Apr 30 '09 at 17:57
  • 6
    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 Apr 30 '09 at 18:34
  • 1
    Couldn't agree more, singletons are often used by programmers who are somehow ashamed of using globals. – laurent Jun 01 '12 at 08:44
  • imho global variables usage is more obscure than having a DB db = get_db_instance() – gpilotino Jul 02 '12 at 19:47
  • Does not answer OP's question. C++ has global variables too; would you apply the same logic and recommend global variables over a Singleton in C++? Please refer to the ample documentation for the reasons to use a Singleton over instance variables. Consider that C++ *compilers* were first written in 'C'. – Technophile Feb 15 '18 at 19:33
19

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
  • 11,147
  • 11
  • 58
  • 104
  • Is the line `static struct A *instance = NULL;` basically only executed at the first invocation of `getObject()`? – Mehdi Charife Aug 19 '23 at 11:48
  • 1
    That's correct, the first time code execution enters the function block it will initialize the static variable, and never again. – justinhj Aug 20 '23 at 16:29
5

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
  • 54,279
  • 5
  • 125
  • 144
  • +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 Apr 29 '09 at 18:55
  • True, if that's not possible you need to use a heavier solution, like a lock. – Michael Apr 29 '09 at 19:02
  • 1
    On a sytem with pthreads, one can use pthread_once() to run the initialization code only once. – Blair Zajac Apr 29 '09 at 20:06
  • Vista added IninitOnceExecuteOnce as well, but that eliminates XP or 2k3. – Michael Apr 29 '09 at 20:12
3

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.

  • It seems safer to use accessor functions rather than global non static variables. – Technophile Feb 15 '18 at 19:41
  • @Technophile It's not safer, it's more flexible. If you're giving access to a variable you're giving access to a variable, doesn't matter if it's direct access or via accessor function. The benefit of using accessor functions is that you can implement additional policy beyond straightforward I/O. –  Feb 18 '18 at 12:10
  • 'Safer' in terms of at least funneling access through an API, which can be extended with validity checks, etc. Is this what you mean by "additional policy"? – Technophile Feb 26 '18 at 13:35
  • Yes that is what I meant –  Apr 01 '18 at 14:21
0

I think this solution might be the simplest and best for most use cases...

In this example, I am creating a single instance global dispatch queue, which you'd definitely do, say, if you were tracking dispatch source events from multiple objects; in that case, every object listening to the queue for events could be notified when a new task is added to the queue. Once the global queue is set (via queue_ref()), it can be referenced with the queue variable in any file in which the header file is included (examples are provided below).

In one of my implementations, I called queue_ref() in AppDelegate.m (main.c would work, too). That way, queue will be initialized before any other calling object attempts to access it. In the remaining objects, I simply called queue. Returning a value from a variable is much faster than calling a function, and then checking the value of the variable before returning it.

In GlobalQueue.h:

#ifndef GlobalQueue_h
#define GlobalQueue_h

#include <stdio.h>
#include <dispatch/dispatch.h>

extern dispatch_queue_t queue;

extern dispatch_queue_t queue_ref(void);

#endif /* GlobalQueue_h */

In GlobalQueue.c:

#include "GlobalQueue.h"

dispatch_queue_t queue;

dispatch_queue_t queue_ref(void) {
    if (!queue) {
        queue = dispatch_queue_create_with_target("GlobalDispatchQueue", DISPATCH_QUEUE_SERIAL, dispatch_get_main_queue());
    }
    
    return queue;
}

To use:

  1. #include "GlobalQueue.h" in any Objective-C or C implementation source file.
  2. Call queue_ref() to use the dispatch queue. Once queue_ref() has been called, the queue can be used via the queue variable in all source files

Examples:

Calling queue_ref():

dispatch_queue_t serial_queue_with_queue_target = dispatch_queue_create_with_target("serial_queue_with_queue_target", DISPATCH_QUEUE_SERIAL, **queue_ref()**);

Calling queue:

dispatch_queue_t serial_queue_with_queue_target = dispatch_queue_create_with_target("serial_queue_with_queue_target", DISPATCH_QUEUE_SERIAL, **queue**));]  
James Bush
  • 1,485
  • 14
  • 19
-3

Just do

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

which works in a concurrent environment too.

nbro
  • 15,395
  • 32
  • 113
  • 196
Jason
  • 215
  • 3
  • 1