Reading about C singletons in a cozy cafe.

10 Singletons in C

Here are ten different examples of implementing the Singleton pattern in C, each with a unique approach.

Table of Contents

Example 1: Basic Singleton

#include <stdio.h>
#include <stdlib.h>

// Singleton instance
typedef struct {
    int data;
} Singleton;

static Singleton* instance = NULL;

Singleton* get_instance() {
    if (instance == NULL) {
        instance = (Singleton*)malloc(sizeof(Singleton));
        instance->data = 0;
    }
    return instance;
}

int main() {
    Singleton* s1 = get_instance();
    Singleton* s2 = get_instance();

    s1->data = 42;

    printf("s1 data: %d\n", s1->data);
    printf("s2 data (should be the same): %d\n", s2->data);

    return 0;
}

Example 2: Thread-Safe Singleton (POSIX Threads)

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

// Singleton instance
typedef struct {
    int data;
} Singleton;

static Singleton* instance = NULL;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

Singleton* get_instance() {
    pthread_mutex_lock(&mutex);
    if (instance == NULL) {
        instance = (Singleton*)malloc(sizeof(Singleton));
        instance->data = 0;
    }
    pthread_mutex_unlock(&mutex);
    return instance;
}

int main() {
    Singleton* s1 = get_instance();
    Singleton* s2 = get_instance();

    s1->data = 42;

    printf("s1 data: %d\n", s1->data);
    printf("s2 data (should be the same): %d\n", s2->data);

    return 0;
}

Example 3: Lazy Singleton with Double-Checked Locking

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

// Singleton instance
typedef struct {
    int data;
} Singleton;

static Singleton* instance = NULL;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

Singleton* get_instance() {
    if (instance == NULL) {
        pthread_mutex_lock(&mutex);
        if (instance == NULL) {
            instance = (Singleton*)malloc(sizeof(Singleton));
            instance->data = 0;
        }
        pthread_mutex_unlock(&mutex);
    }
    return instance;
}

int main() {
    Singleton* s1 = get_instance();
    Singleton* s2 = get_instance();

    s1->data = 42;

    printf("s1 data: %d\n", s1->data);
    printf("s2 data (should be the same): %d\n", s2->data);

    return 0;
}

Example 4: Static Initialization (C99)

#include <stdio.h>
#include <stdlib.h>

// Singleton instance
typedef struct {
    int data;
} Singleton;

static Singleton instance = {.data = 0};

Singleton* get_instance() {
    return &instance;
}

int main() {
    Singleton* s1 = get_instance();
    Singleton* s2 = get_instance();

    s1->data = 42;

    printf("s1 data: %d\n", s1->data);
    printf("s2 data (should be the same): %d\n", s2->data);

    return 0;
}

Example 5: Function-Scoped Static Variable (C99)

#include <stdio.h>

Singleton* get_instance() {
    static Singleton instance = {.data = 0};
    return &instance;
}

int main() {
    Singleton* s1 = get_instance();
    Singleton* s2 = get_instance();

    s1->data = 42;

    printf("s1 data: %d\n", s1->data);
    printf("s2 data (should be the same): %d\n", s2->data);

    return 0;
}

Example 6: Singleton with Destructor

#include <stdio.h>
#include <stdlib.h>

// Singleton instance
typedef struct {
    int data;
} Singleton;

static Singleton* instance = NULL;

void cleanup() {
    if (instance != NULL) {
        free(instance);
        instance = NULL;
    }
}

Singleton* get_instance() {
    if (instance == NULL) {
        instance = (Singleton*)malloc(sizeof(Singleton));
        atexit(cleanup);
        instance->data = 0;
    }
    return instance;
}

int main() {
    Singleton* s1 = get_instance();
    Singleton* s2 = get_instance();

    s1->data = 42;

    printf("s1 data: %d\n", s1->data);
    printf("s2 data (should be the same): %d\n", s2->data);

    return 0;
}

**Example 7: Singleton with Resource Management**

#include <stdio.h>
#include <stdlib.h>

// Singleton instance
typedef struct {
    int data;
} Singleton;

static Singleton* instance = NULL;

void cleanup() {
    if (instance != NULL) {
        free(instance);
        instance = NULL;
    }
}

void initialize() {
    if (instance == NULL) {
        instance = (Singleton*)malloc(sizeof(Singleton));
        atexit(cleanup);
        instance->data = 0;
    }
}

Singleton* get_instance() {
    initialize();
    return instance;
}

int main() {
    Singleton* s1 = get_instance();
    Singleton* s2 = get_instance();

    s1->data = 42;

    printf("s1 data: %d\n", s1->data);
    printf("s2 data (should be the same): %d\n", s2->data);

    return 0;
}

Example 8: Singleton Using a Global Variable

#include <stdio.h>

// Singleton instance (global)
Singleton instance = {.data = 0};

Singleton* get_instance() {
    return &instance;
}

int main() {
    Singleton* s1 = get_instance();
    Singleton* s2 = get_instance();

    s1->data = 42;

    printf("s1 data: %d\n", s1->data);
    printf("s2 data (should be the same): %d\n", s2->data);

    return 0;
}

Example 9: Singleton with Mutex (POSIX Threads)

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

// Singleton instance
typedef struct {
    int data;
} Singleton;

static Singleton* instance = NULL;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

Singleton* get_instance() {
    pthread_mutex_lock(&mutex);
    if (instance == NULL) {
        instance = (Singleton*)malloc(sizeof(Singleton));
        instance->data = 0;
    }
    pthread_mutex_unlock(&mutex);
    return instance;
}

int main() {
    Singleton* s1 = get_instance();
    Singleton* s2 = get_instance();

    s1->data = 42;

    printf("s1 data: %d\n", s1->data);
    printf("s2 data (should be the same): %d\n", s2->data);

    return 0;
}

Example 10: Singleton with Atomic Operations (C11)

#include <stdio.h>
#include <stdatomic.h>

// Singleton instance
typedef struct {
    int data;
} Singleton;

static atomic_flag lock = ATOMIC_FLAG_INIT;
static Singleton* instance = NULL;

Singleton* get_instance() {
    while (atomic_flag_test_and_set(&lock)) {}
    if (instance == NULL) {
        instance = (Singleton*)malloc(sizeof(Singleton));
        instance->data = 0;
    }
    atomic_flag_clear(&lock);
    return instance;
}

int main() {
    Singleton* s1 = get_instance();
    Singleton* s2 = get_instance();

    s1->data = 42;

    printf("s1 data: %d\n", s1->data);
    printf("s2 data (should be the same): %d\n", s2->data);

    return 0;
}
Dane Stuckel Photo
Written and maintained by Dane Stuckel.
To like, comment or give feedback,
please share on social media.
Follow the author for more content like this.