web-dev-qa-db-ja.com

Cでシングルトンを作成する方法は?

Cでシングルトンを作成するための最良の方法は何ですか?並行ソリューションはNiceです。

Cがシングルトンに使用する最初の言語ではないことを私は知っています。

25
Liran Orevi

まず、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;
}

そして最後に、シングルトンはほとんど乱用されていることを忘れないでください。特にマルチスレッド環境では、それらを正しくすることは困難です...

30
dirkgently

あなたはする必要はありません。 Cにはすでにグローバル変数があるため、それらをシミュレートするための回避策は必要ありません。

19
Adam Jaskiewicz

これは、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;
};

シングルトンを解放する関数も必要になることに注意してください。特に、プロセスの終了時に自動的に解放されないシステムリソースを取得する場合。

14
justinhj

編集:私の答えは、あなたが作成しているシングルトンがやや複雑で、複数のステップの作成プロセスがあることを前提としています。静的データだけの場合は、他の人が提案しているようにグローバルを使用してください。

Cのシングルトンは非常に奇妙になります。 。 。特にエレガントに見える「オブジェクト指向C」の例を見たことがありません。可能であれば、C++の使用を検討してください。 C++を使用すると、使用する機能を選択できます。多くの人は、C++を「より優れたC」として使用しています。

以下は、ロックフリーの1回限りの初期化の非常に典型的なパターンです。前の値がnullの場合、InterlockCompareExchangePtrは新しい値をアトミックにスワップします。これにより、複数のスレッドが同時にシングルトンを作成しようとしても、1つだけが勝ちます。他の人は新しく作成されたオブジェクトを削除します。

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
Michael

別の見方をすると、Cプログラム内のすべてのファイルは、事実上、実行時に自動インスタンス化され、サブクラス化できないシングルトンクラスです。

  • グローバル静的変数は、プライベートクラスのメンバーです。
  • グローバル非静的はパブリックです(ヘッダーファイルでexternを使用して宣言するだけです)。
  • 静的関数はプライベートメソッドです
  • 非静的関数はパブリック関数です。

すべてに適切なプレフィックスを付けると、my_singleton_method()の代わりにmy_singleton.method()を使用できるようになります。

シングルトンが複雑な場合は、使用する前にgenerate_singleton()メソッドを記述して初期化できますが、他のすべてのパブリックメソッドが呼び出されたかどうかを確認し、呼び出されなかった場合はエラーになるようにする必要があります。

2
user4209701