如何在C中创建一个单例?

时间:2022-09-02 08:46:11

What's the best way to create a singleton in C? A concurrent solution would be nice.

在C中创建单例的最好方法是什么?并发解决方案会更好。

I am aware that C isn't the first language you would use for a singleton.

我知道C不是单例语言的第一语言。

6 个解决方案

#1


27  

First, C is not suitable for OO programming. You'd be fighting all the way if you do. Secondly, singletons are just static variables with some encapsulation. So you can use a static global variable. However, global variables typically have far too many ills associated with them. You could otherwise use a function local static variable, like this:

首先,C不适合OO编程。如果你这么做的话,你会一直在打架。其次,单例是具有某种封装性的静态变量。你可以使用静态全局变量。然而,全局变量通常有太多与之相关的问题。否则可以使用函数局部静态变量,如:

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

or a smarter 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;
}

And finally, remember, that singletons are mostly abused. It is difficult to get them right, especially under multi-threaded environments...

最后,记住,单身的人大多被虐待。很难正确处理它们,尤其是在多线程环境中……

#2


17  

You don't need to. C already has global variables, so you don't need a work-around to simulate them.

你不需要。C已经有全局变量,所以你不需要一个工作来模拟它们。

#3


13  

It's the same as the C++ version pretty much. Just have a function that returns an instance pointer. It can be a static variable inside the function. Wrap the function body with a critical section or pthread mutex, depending on platform.

它和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;
};

Note that you'd need a function to free up the singleton too. Especially if it grabs any system resources that aren't automatically released on process exit.

注意,您还需要一个函数来释放单例对象。特别是如果它捕获了在进程退出时没有自动释放的任何系统资源。

#4


5  

EDIT: My answer presumes the singleton you are creating is somewhat complex and has a multi-step creation process. If it's just static data, go with a global like others have suggested.

编辑:我的回答假设您正在创建的单例对象有点复杂,并且具有多步创建过程。如果只是静态数据,就像其他人建议的那样使用全局数据。

A singleton in C will be very weird . . . I've never seen an example of "object oriented C" that looked particularly elegant. If possible, consider using C++. C++ allows you to pick and choose which features you want to use, and many people just use it as a "better C".

C中的单例会非常奇怪……我从未见过一个“面向对象的C”的例子,它看起来特别优雅。如果可能的话,考虑使用c++。c++允许您选择和选择您想要使用的特性,许多人只是把它作为“更好的C”使用。

Below is a pretty typical pattern for lock-free one-time initialization. The InterlockCompareExchangePtr atomically swaps in the new value if the previous is null. This protects if multiple threads try to create the singleton at the same time, only one will win. The others will delete their newly created object.

下面是一个非常典型的无锁一次性初始化模式。如果之前的值为空,则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());

#5


2  

Here's another perspective: every file in a C program is effectively a singleton class that is auto instantiated at runtime and cannot be subclassed.

这里还有另一种观点:C程序中的每个文件实际上都是一个单例类,在运行时自动实例化,不能子类化。

  • Global static variables are your private class members.
  • 全局静态变量是您的私有类成员。
  • Global non static are public (just declare them using extern in some header file).
  • 全局非静态是公共的(只需在一些头文件中使用extern声明它们)。
  • Static functions are private methods
  • 静态函数是私有方法
  • Non-static functions are the public ones.
  • 非静态函数是公共函数。

Give everything a proper prefix and now you can use my_singleton_method() in lieu of my_singleton.method().

给一切都加上一个合适的前缀,现在可以使用my_my_singleton_method()代替my_singleton.method()。

If your singleton is complex you can write a generate_singleton() method to initialize it before use, but then you need to make sure all the other public methods check if it was called and error out if not.

如果您的singleton是复杂的,您可以在使用之前编写generate_singleton()方法来初始化它,但是您需要确保所有其他的公共方法检查它是否被调用和错误。

#6


-2  

Just do

只做

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

which works in a concurrent environment too.

在并发环境中也可以工作。

#1


27  

First, C is not suitable for OO programming. You'd be fighting all the way if you do. Secondly, singletons are just static variables with some encapsulation. So you can use a static global variable. However, global variables typically have far too many ills associated with them. You could otherwise use a function local static variable, like this:

首先,C不适合OO编程。如果你这么做的话,你会一直在打架。其次,单例是具有某种封装性的静态变量。你可以使用静态全局变量。然而,全局变量通常有太多与之相关的问题。否则可以使用函数局部静态变量,如:

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

or a smarter 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;
}

And finally, remember, that singletons are mostly abused. It is difficult to get them right, especially under multi-threaded environments...

最后,记住,单身的人大多被虐待。很难正确处理它们,尤其是在多线程环境中……

#2


17  

You don't need to. C already has global variables, so you don't need a work-around to simulate them.

你不需要。C已经有全局变量,所以你不需要一个工作来模拟它们。

#3


13  

It's the same as the C++ version pretty much. Just have a function that returns an instance pointer. It can be a static variable inside the function. Wrap the function body with a critical section or pthread mutex, depending on platform.

它和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;
};

Note that you'd need a function to free up the singleton too. Especially if it grabs any system resources that aren't automatically released on process exit.

注意,您还需要一个函数来释放单例对象。特别是如果它捕获了在进程退出时没有自动释放的任何系统资源。

#4


5  

EDIT: My answer presumes the singleton you are creating is somewhat complex and has a multi-step creation process. If it's just static data, go with a global like others have suggested.

编辑:我的回答假设您正在创建的单例对象有点复杂,并且具有多步创建过程。如果只是静态数据,就像其他人建议的那样使用全局数据。

A singleton in C will be very weird . . . I've never seen an example of "object oriented C" that looked particularly elegant. If possible, consider using C++. C++ allows you to pick and choose which features you want to use, and many people just use it as a "better C".

C中的单例会非常奇怪……我从未见过一个“面向对象的C”的例子,它看起来特别优雅。如果可能的话,考虑使用c++。c++允许您选择和选择您想要使用的特性,许多人只是把它作为“更好的C”使用。

Below is a pretty typical pattern for lock-free one-time initialization. The InterlockCompareExchangePtr atomically swaps in the new value if the previous is null. This protects if multiple threads try to create the singleton at the same time, only one will win. The others will delete their newly created object.

下面是一个非常典型的无锁一次性初始化模式。如果之前的值为空,则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());

#5


2  

Here's another perspective: every file in a C program is effectively a singleton class that is auto instantiated at runtime and cannot be subclassed.

这里还有另一种观点:C程序中的每个文件实际上都是一个单例类,在运行时自动实例化,不能子类化。

  • Global static variables are your private class members.
  • 全局静态变量是您的私有类成员。
  • Global non static are public (just declare them using extern in some header file).
  • 全局非静态是公共的(只需在一些头文件中使用extern声明它们)。
  • Static functions are private methods
  • 静态函数是私有方法
  • Non-static functions are the public ones.
  • 非静态函数是公共函数。

Give everything a proper prefix and now you can use my_singleton_method() in lieu of my_singleton.method().

给一切都加上一个合适的前缀,现在可以使用my_my_singleton_method()代替my_singleton.method()。

If your singleton is complex you can write a generate_singleton() method to initialize it before use, but then you need to make sure all the other public methods check if it was called and error out if not.

如果您的singleton是复杂的,您可以在使用之前编写generate_singleton()方法来初始化它,但是您需要确保所有其他的公共方法检查它是否被调用和错误。

#6


-2  

Just do

只做

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

which works in a concurrent environment too.

在并发环境中也可以工作。