Как лучше всего создать синглтон в C? Параллельное решение было бы неплохо.
Я знаю, что C — не первый язык, который вы бы использовали для синглтона.
Как лучше всего создать синглтон в 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 атомарно заменяет новое значение, если предыдущее равно 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());
Вот еще одна точка зрения: каждый файл в программе на C фактически представляет собой одноэлементный класс, который автоматически создается во время выполнения и не может быть подклассом.
extern в каком-нибудь заголовочном файле).Дайте всем правильный префикс, и теперь вы можете использовать my_singleton_method() вместо my_singleton.method().
Если ваш синглтон сложный, вы можете написать метод generate_singleton() для его инициализации перед использованием, но тогда вам нужно убедиться, что все другие общедоступные методы проверяют, был ли он вызван, и выдают ошибку, если нет.
Я думаю, что это решение может быть самым простым и лучшим для большинства случаев использования...
В этом примере я создаю глобальную очередь отправки с одним экземпляром, что вы определенно сделали бы, скажем, если бы отслеживали события источника отправки из нескольких объектов; в этом случае каждый объект, прослушивающий очередь событий, может быть уведомлен, когда в очередь добавляется новая задача. Как только глобальная очередь установлена (через queue_ref()), на нее можно ссылаться с помощью переменной queue в любом файле, в который включен заголовочный файл (примеры приведены ниже).
В одной из своих реализаций я вызывал queue_ref() в AppDelegate.m (main.c тоже подойдет). Таким образом, queue будет инициализирован до того, как любой другой вызывающий объект попытается получить к нему доступ. В остальных объектах я просто назвал queue. Возврат значения из переменной выполняется намного быстрее, чем вызов функции с последующей проверкой значения переменной перед ее возвратом.
В 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 */
В 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;
}
Использовать:
#include "GlobalQueue.h" в любом исходном файле реализации Objective-C или C.queue_ref(), чтобы использовать очередь отправки. После вызова queue_ref() очередь может использоваться через переменную queue во всех исходных файлах.Примеры:
Вызов 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()**);
Очередь звонков:
dispatch_queue_t serial_queue_with_queue_target = dispatch_queue_create_with_target("serial_queue_with_queue_target", DISPATCH_QUEUE_SERIAL, **queue**));]
Просто делать
void * getSingleTon() {
static Class object = (Class *)malloc( sizeof( Class ) );
return &object;
}
который также работает в параллельной среде.
static Class * object = ...; return object;.
- person alk; 07.09.2015