web-dev-qa-db-ja.com

静的メンバー関数とスレッドセーフ

静的メンバー関数で作成されたオブジェクトと変数は、メンバー関数の場合のように「ローカル」とは見なされないため、複数のスレッド間で共有できるようになりました。

一方、オブジェクトを作成するメンバー関数がある場合、これはスレッドに対してローカルであるため、共有されません。

私はこれを言うのは正しいですか?

18
Tony The Lion

いいえ、あなたは正しくありません。

静的関数で作成されたオブジェクト共有されません共有されます。これは通常の関数にも当てはまります。

ただし、オブジェクト自体が静的であると宣言されている場合はオブジェクトを共有でき、関数が静的であるかどうかには依存しません。

void myFunc()
{
    static MyObject o;
    o.CallMethod(); // here o is shared by all threads calling myFunc
}

オブジェクトが静的であると宣言されると、オブジェクトがグローバル変数であるかのようになりますが、宣言された関数のスコープでのみ表示されます。

19

このクラスを検討してください

_class CData
{
public:
    static void func()
    {
        int a;
        static int b;
    }

    int c;
    static int d;
};

int main()
{
    CData::func();
}
_

これで、変数afunc()の各呼び出しに対してローカルになります。 2つのスレッドが同時にfunc()を呼び出すと、異なるバージョンのaを取得します。

bは静的ローカルです。値は、func()の異なる呼び出し間で保持されます。 2つのスレッドが同時にfunc()を呼び出す場合、それらは同じバージョンのbにアクセスするため、同期を行う必要がある場合があります。

cはインスタンス変数です。これは、CDataの特定のインスタンス化に関連付けられています。 func()cにアクセスできません。ただし、以下に示すトリックを除きます。

dは静的変数です。クラスCDataのすべての使用間で共有されるdのインスタンスが1つあるため、同期が必要になる場合があります。静的関数func()から簡単に使用できます。

静的関数からインスタンスデータにアクセスするために使用されるトリックは、有効なオブジェクトを関数に渡すことです。

例えば.

_class CData
{
public:
    static void func(CData *p)
    {
        int a;
        static int b;

        b = p->c;
    }

    int c;
    static int d;
};

int main()
{
    CData data;
    CData::func(&data);
}
_

お役に立てば幸いです。

40
Michael J

いいえ、あなたは正しくありません。そして、はい、C++は「静的」という言葉を非常に使いすぎています。

もちろん、静的クラスメンバー変数はグローバルであり、クラスは名前空間スコープとして機能し、プライベートまたは保護されている場合はアクセス権限にいくつかの違いがあります(クラスからのみアクセスできます)。

ただし、静的クラスメンバー関数は、通常のフリー関数(クラスメンバーではない)と同じであり、呼び出されるたびに独自のローカル変数を持ちます。

静的クラスメンバー関数と通常のフリー関数の唯一の本当の違いは、命名規則は別として、クラスのプライベートメンバーにアクセスできることです(外部の「インスタンス」が必要です)。

さらに、静的クラスメンバー関数は、可変テンプレートパラメータを使用してテンプレートから呼び出すことができ、一般に「コンパイル時ポリモーフィズム」と呼ばれ、メタプログラミングで一般的に使用されます。

一方、関数の静的「ローカル」変数は単一インスタンスですが、グローバルに少し似ており、関数を呼び出す2つのスレッドが同じインスタンスにアクセスするため、スレッド競合の問題に敏感です。

3
CashCow

関数が静的であるかどうかは関係ありません(クラスメソッド)。自動変数のみが関数に対してlocalと見なされます。それらのデータのアドレスを知っている場合は、それにアクセスできます。

あなたは例えばを使用することができます thread-local storage 出力を専用のスレッドコンテキストに割り当てます。

1
Raphael Bossek