Подтвердить что ты не робот

Как создать Singleton в C?

Какой лучший способ создать синглтон в C? Сопутствующее решение было бы приятным.

Я знаю, что C не является первым языком, который вы бы использовали для синглета.

4b9b3361

Ответ 1

Во-первых, C не подходит для программирования OO. Если вы это сделаете, вы будете сражаться. Во-вторых, синглтоны - это просто статические переменные с некоторой инкапсуляцией. Таким образом, вы можете использовать статическую глобальную переменную. Однако глобальные переменные, как правило, имеют слишком много проблем, связанных с ними. В противном случае вы могли бы использовать локальную статическую переменную функции, например:

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

или более умный макрос:

#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;
}

И, наконец, помните, что синглетоны в основном злоупотребляют. Трудно получить их право, особенно в многопоточных средах...

Ответ 2

Вам не нужно. C уже имеет глобальные переменные, поэтому вам не нужно работать, чтобы имитировать их.

Ответ 3

Это то же самое, что и версия на С++. Просто имейте функцию, которая возвращает указатель экземпляра. Это может быть статическая переменная внутри функции. Оберните тело функции критической секцией или мьютексом pthread, в зависимости от платформы.

#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;
};

Обратите внимание, что вам понадобится функция для освобождения синглтона. Особенно, если он захватывает любые системные ресурсы, которые автоматически не отпускаются при выходе из процесса.

Ответ 4

EDIT: Мой ответ предполагает, что созданный вами singleton несколько сложный и имеет многоэтапный процесс создания. Если это просто статические данные, идите с глобальным, как это предполагали другие.

Синтаксис в C будет очень странным., Я никогда не видел пример "объектно-ориентированного С", который выглядел особенно элегантно. Если возможно, рассмотрите возможность использования С++. С++ позволяет вам выбирать, какие функции вы хотите использовать, и многие люди просто используют его как "лучше C".

Ниже представлен довольно типичный шаблон для однократной инициализации без блокировки. InterlockCompareExchangePtr атомарно меняет местами новое значение, если предыдущее значение равно null. Это защищает, если несколько потоков пытаются создать синглтон одновременно, победит только один. Остальные удалят их вновь созданный объект.

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());

Ответ 5

Здесь другая перспектива: каждый файл в программе на C - это класс Singleton, который автоматически создается при запуске и не может быть подклассом.

  • Глобальные статические переменные - ваши частные члены класса.
  • Глобальные нестатические общедоступны (просто объявляйте их с помощью extern в каком-то заголовочном файле).
  • Статические функции - частные методы.
  • Нестатические функции являются общедоступными.

Дайте всем правильный префикс, и теперь вы можете использовать my_singleton_method() вместо my_singleton.method().

Если ваш синглтон сложный, вы можете написать метод generate_singleton() для его инициализации перед использованием, но затем вам нужно убедиться, что все остальные общедоступные методы проверяют, было ли оно вызвано и ошибка, если нет.

Ответ 6

Просто сделай

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

который также работает в параллельной среде.