Pergunta

Qual é a melhor maneira de criar um singleton em C? Uma solução simultânea seria agradável.

Estou ciente de que C não é a primeira língua que você usaria para um singleton.

Foi útil?

Solução

Primeiro, C não é adequado para a programação OO. Você estaria lutando por todo o caminho se você fizer. Em segundo lugar, singletons são variáveis ??apenas estáticas com alguns encapsulamento. Assim você pode usar uma variável global estática. No entanto, variáveis ??globais normalmente têm demasiados males associados a eles. Caso contrário, pode usar uma variável estática local função, assim:

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

ou uma forma mais inteligente macro:

#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, finalmente, lembre-se, que singletons são mais abusadas. É difícil obtê-los direito, especialmente sob multi-threaded ambientes ...

Outras dicas

Você não precisa. C já tem variáveis ??globais, para que você não precisa de uma solução alternativa para simular-los.

É o mesmo que a versão do C ++ praticamente. Basta ter uma função que retorna um ponteiro de instância. Pode ser uma variável estática dentro da função. Envolva o corpo da função com uma seção crítica ou mutex pthread, dependendo da 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;
};

Note que você precisa de uma função para liberar o singleton também. Especialmente se ele pega todos os recursos do sistema que não são liberados automaticamente saída do processo.

EDIT: Minha resposta presume o singleton você está criando é um pouco complexo e tem um processo de criação de multi-passo. Se é apenas dados estáticos, vá com um global como já foi sugerido.

Um singleton em C vai ser muito estranho. . . Eu nunca vi um exemplo de "orientada a objeto C" que parecia particularmente elegante. Se possível, considere o uso C ++. C ++ permite-lhe escolher quais as características que você deseja usar, e muitas pessoas simplesmente usá-lo como um "melhor C".

Segue-se um padrão bastante típico para inicialização em tempo um livre-lock. O InterlockCompareExchangePtr troca atomicamente no novo valor se o anterior é nulo. Isso protege se vários segmentos tentam criar o Singleton, ao mesmo tempo, apenas um vai ganhar. Os outros irão eliminar seu objeto recém-criado.

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

Aqui está uma outra perspectiva:. Cada arquivo em um programa C é efetivamente uma única classe que é auto instanciado em tempo de execução e não pode ser uma subclasse

  • variáveis ??estáticas globais são os membros de sua classe privadas.
  • Global não estática são públicos (apenas declará-los usando extern em algum arquivo de cabeçalho).
  • funções estáticas são métodos privados
  • As funções não-estático são as públicas.

dar tudo um prefixo adequada e agora você pode usar my_singleton_method() em vez de my_singleton.method().

Se o seu singleton é complexo, você pode escrever um método generate_singleton() para inicializar-lo antes de usar, mas então você precisa se certificar de todos os outros métodos públicos verificar se ele foi chamado e erro, se não.

Apenas faça

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

que trabalha em um ambiente concorrente também.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top