Pregunta

¿Cuál es la mejor manera de crear un singleton en C? Una solución concurrente sería buena.

Soy consciente de que C no es el primer lenguaje que usarías para un singleton.

¿Fue útil?

Solución

Primero, C no es adecuado para la programación OO. Estarás peleando todo el camino si lo haces. En segundo lugar, los singletons son solo variables estáticas con cierta encapsulación. Entonces puede usar una variable global estática. Sin embargo, las variables globales generalmente tienen demasiados males asociados con ellas. De lo contrario, podría utilizar una función variable estática local, como esta:

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

o una macro más inteligente:

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

Y finalmente, recuerde, que los singletons son abusados ??en su mayoría. Es difícil hacerlos bien, especialmente en entornos de subprocesos múltiples ...

Otros consejos

No necesitas hacerlo. C ya tiene variables globales, por lo que no necesita una solución alternativa para simularlas.

Es casi lo mismo que la versión C ++. Solo tiene una función que devuelve un puntero de instancia. Puede ser una variable estática dentro de la función. Envuelva el cuerpo de la función con una sección crítica o mutex pthread, dependiendo de la plataforma.

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

Tenga en cuenta que también necesitaría una función para liberar el singleton. Especialmente si captura los recursos del sistema que no se liberan automáticamente al salir del proceso.

EDITAR: Mi respuesta supone que el singleton que está creando es algo complejo y tiene un proceso de creación de varios pasos. Si solo se trata de datos estáticos, elija uno global como otros han sugerido.

Un singleton en C será muy raro. . . Nunca he visto un ejemplo de '' C orientado a objetos '' eso se veía particularmente elegante. Si es posible, considere usar C ++. C ++ le permite elegir qué características desea usar, y muchas personas simplemente lo usan como una "mejor C".

A continuación se muestra un patrón bastante típico para la inicialización única sin bloqueo. InterlockCompareExchangePtr intercambia atómicamente el nuevo valor si el anterior es nulo. Esto protege si varios hilos intentan crear el singleton al mismo tiempo, solo uno ganará. Los demás eliminarán su objeto recién creado.

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

Aquí hay otra perspectiva: cada archivo en un programa en C es efectivamente una clase singleton que se instancia automáticamente en tiempo de ejecución y no se puede subclasificar.

  • Las variables globales estáticas son miembros de su clase privada.
  • Global no estático es público (solo declare usando extern en algún archivo de encabezado).
  • Las funciones estáticas son métodos privados
  • Las funciones no estáticas son las públicas.

Déle a todo un prefijo apropiado y ahora puede usar my_singleton_method () en lugar de my_singleton.method () .

Si su singleton es complejo, puede escribir un método generate_singleton () para inicializarlo antes de usarlo, pero luego debe asegurarse de que todos los demás métodos públicos verifiquen si se llamó y si no.

Solo hazlo

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

que también funciona en un entorno concurrente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top