代码之家  ›  专栏  ›  技术社区  ›  Liran Orevi

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

  •  21
  • Liran Orevi  · 技术社区  · 17 年前

    在C语言中创建单例的最佳方法是什么?并发解决方案是不错的。

    我知道C并不是你一个人会使用的第一种语言。

    6 回复  |  直到 9 年前
        1
  •  28
  •   Michele Spagnuolo    14 年前

    首先,C不适合OO编程。如果你这样做的话,你会一直在战斗。其次,单例只是一些封装的静态变量。所以可以使用静态全局变量。然而,全局变量通常有太多与之相关的问题。否则,可以使用函数局部静态变量,如下所示:

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

    最后,记住,独生子女大多被虐待。很难纠正它们,尤其是在多线程环境下…

        2
  •  18
  •   Adam Jaskiewicz    17 年前

    你不需要。C已经有了全局变量,所以您不需要四处工作来模拟它们。

        3
  •  14
  •   justinhj    17 年前

    它和C++版本差不多。只需要一个返回实例指针的函数。它可以是函数内部的静态变量。根据平台的不同,用关键部分或pthread mutex包装函数体。

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

    请注意,您还需要一个函数来释放单例。尤其是当它获取了任何在进程退出时不会自动释放的系统资源时。

        4
  •  5
  •   Michael    17 年前

    编辑:我的答案假设您正在创建的单例有点复杂,并且有一个多步骤的创建过程。如果它只是静态数据,那么使用其他人建议的全局数据。

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

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

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

    • 全局静态变量是私有类成员。
    • 全局非静态是公共的(只需使用 extern 在一些头文件中)。
    • 静态函数是私有方法
    • 非静态功能是公共功能。

    给所有的东西一个合适的前缀,现在你可以使用 my_singleton_method() 代替 my_singleton.method() .

    如果你的单身汉很复杂,你可以写一个 generate_singleton() 方法在使用前对其进行初始化,但需要确保所有其他公共方法都检查是否调用了该方法,否则将出错。

        6
  •  -2
  •   nbro kai    9 年前

    只要做

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

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