2

C++ でのシングルトンおよびマルチスレッド プログラミングに関連する疑問があります。以下に、shared という名前の変数を持つシングルトン クラスのコード例を示します。

シングルトン グローバル インスタンスのその変数を変更 (+1) する 1000 個のスレッドを作成します。shared の最終値は 1000 ですが、この変数を同時実行のために保護していないため、この値は 1000 未満になると予想されます。

クラスがシングルトンであるため、コードは本当にスレッドセーフですか?それともたまたま幸運で値が 1000 であっても、完全に 1000 未満になる可能性がありますか?

#include <iostream>
using namespace std;

class Singleton {
private:
    Singleton() {shared = 0;};
    static Singleton * _instance;
    int shared;

public:
    static Singleton* Instance();
    void increaseShared () { shared++; };
    int getSharedValue () { return shared; };
};

// Global static pointer used to ensure a single instance of the class.
Singleton* Singleton::_instance = NULL;

Singleton * Singleton::Instance() {
    if (!_instance) { 
        _instance = new Singleton;
    }

    return _instance;
}

void * myThreadCode (void * param) {
    Singleton * theInstance;
    theInstance = Singleton::Instance();
    theInstance->increaseShared();

    return NULL;
}

int main(int argc, const char * argv[]) {
    pthread_t threads[1000];
    Singleton * theInstance = Singleton::Instance();

    for (int i=0; i<1000; i++) {
        pthread_create(&threads[i], NULL, &myThreadCode, NULL);
    }

    cout << "The shared value is: " << theInstance->getSharedValue() << endl;

    return 0;
}
4

2 に答える 2

5

クラスがシングルトンであるため、コードは本当にスレッドセーフですか?それともたまたま幸運で値が 1000 であっても、完全に 1000 未満になる可能性がありますか?

あなたは幸運...

実際には、あなたが観察している最も可能性の高い問題は、特定のマシンでシングルトンの値をインクリメントするのにかかる時間が、オペレーティング システムがリソースを割り当てるのにかかる時間よりも短いという事実に関係しています。個々の pthread を起動します。したがって、2 つのスレッドがシングルトンの保護されていないリソースをめぐって競合するというシナリオには決してなりませんでした。

はるかに優れたテストは、最初にすべての pthread を起動し、それらをバリアまたは条件変数でブロックし、すべてのスレッドが「アクティブ」であるというバリアの条件が満たされたら、シングルトンでインクリメントを実行することでした...その時点で、インクリメント操作のような非アトミック操作で発生する種類のデータ競合を目にする可能性が高くなります。

于 2012-07-17T01:38:30.787 に答える
1

このように実装するSingletonと、シングルトンの作成はスレッドセーフになります。

Singleton & Singleton::Instance() {
    static Singleton instance;
    return instance;
}

インスタンスが null になることはなく、マネージャーへのメモリがないため、ポインターの代わりに参照が返されます。

インクリメント操作は、プラットフォーム固有の操作 (g++ はビルトインを提供します__sync_fetch_and_add

std::atomic<int> shared;

void increaseShared () { ++shared; };
于 2012-07-17T02:06:02.197 に答える