Domanda

Qual è il modo migliore per creare un singleton in C? Una soluzione concorrente sarebbe piacevole.

Sono consapevole che C non è la prima lingua che useresti per un singleton.

È stato utile?

Soluzione

Innanzitutto, C non è adatto per la programmazione OO. Combatteresti fino in fondo se lo fai. In secondo luogo, i singoli sono solo variabili statiche con qualche incapsulamento. Quindi puoi usare una variabile globale statica. Tuttavia, le variabili globali in genere hanno troppi mali associati ad esse. Altrimenti potresti usare una funzione variabile statica locale, come questa:

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

o una macro più intelligente:

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

E infine, ricorda, che i singoli sono abusati per lo più. È difficile risolverli, specialmente in ambienti multi-thread ...

Altri suggerimenti

Non è necessario. C ha già variabili globali, quindi non hai bisogno di una soluzione per simularle.

È praticamente uguale alla versione C ++. Basta avere una funzione che restituisce un puntatore all'istanza. Può essere una variabile statica all'interno della funzione. Avvolgere il corpo della funzione con una sezione critica o pthread mutex, a seconda della piattaforma.

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

Nota che avresti bisogno di una funzione per liberare anche il singleton. Soprattutto se raccoglie risorse di sistema che non vengono automaticamente rilasciate all'uscita dal processo.

EDIT: la mia risposta presume che il singleton che stai creando sia alquanto complesso e abbia un processo di creazione in più passaggi. Se sono solo dati statici, scegli un globale come altri hanno suggerito.

Un singleton in C sarà molto strano. . . Non ho mai visto un esempio di "C orientato agli oggetti" sembrava particolarmente elegante. Se possibile, considera l'utilizzo di C ++. Il C ++ ti permette di scegliere quali caratteristiche vuoi usare e molte persone lo usano semplicemente come un "C" migliore.

Di seguito è riportato un modello abbastanza tipico per l'inizializzazione singola senza blocco. InterlockCompareExchangePtr scambia atomicamente il nuovo valore se il precedente è nullo. Questo protegge se più thread tentano di creare il singleton allo stesso tempo, solo uno vincerà. Gli altri elimineranno il loro oggetto appena creato.

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

Ecco un'altra prospettiva: ogni file in un programma C è effettivamente una classe singleton che viene istanziata automaticamente in fase di esecuzione e non può essere sottoclassata.

  • Le variabili statiche globali sono i membri della tua classe privata.
  • Globali non statici sono pubblici (dichiarali usando extern in alcuni file di intestazione).
  • Le funzioni statiche sono metodi privati ??
  • Le funzioni non statiche sono pubbliche.

Dai a tutto un prefisso adeguato e ora puoi usare my_singleton_method () al posto di my_singleton.method () .

Se il tuo singleton è complesso, puoi scrivere un metodo generate_singleton () per inizializzarlo prima dell'uso, ma poi devi assicurarti che tutti gli altri metodi pubblici controllino se è stato chiamato ed errore se no.

Basta

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

che funziona anche in un ambiente concorrente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top