Вопрос

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

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

Это было полезно?

Решение

Во-первых, 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;
}

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

Другие советы

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

Это во многом то же самое, что и версия для 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;
};

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

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

Синглтон в C будет очень странным...Я никогда не видел примера «объектно-ориентированного 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());

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top