Как создать синглтон в C? - PullRequest
23 голосов
/ 29 апреля 2009

Какой лучший способ создать синглтон в C? Было бы неплохо параллельное решение.

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

Ответы [ 6 ]

29 голосов
/ 29 апреля 2009

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

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

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

18 голосов
/ 29 апреля 2009

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

14 голосов
/ 29 апреля 2009

Это почти то же самое, что и версия C ++. Просто есть функция, которая возвращает указатель экземпляра. Это может быть статическая переменная внутри функции. Оберните тело функции критическим разделом или мьютексом 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;
};

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

5 голосов
/ 29 апреля 2009

РЕДАКТИРОВАТЬ: Мой ответ предполагает, что создаваемый вами синглтон является довольно сложным и имеет многоэтапный процесс создания. Если это просто статические данные, используйте глобальные, как предлагали другие.

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

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

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());
2 голосов
/ 29 марта 2017

Вот еще одна перспектива: каждый файл в программе на Си фактически является одноэлементным классом, который автоматически создается во время выполнения и не может быть разделен на подклассы.

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

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

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

0 голосов
/ 30 апреля 2012

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...