私はスレッドセーフなshared_ptrでクラスを作成しようとしています。私の使用例は、shared_ptrがクラスのオブジェクトに属し、シングルトンのような振る舞いをする(CreateIfNotExist関数は、任意の時点で任意のスレッドで実行できます)。ロックなしでthread_safe shared_ptrを作成する正しい方法はありますか?
ポインタがnullの場合、値を設定する最初のスレッドが勝ち、同時にそのスレッドを作成している他のすべてのスレッドが勝ちスレッドの値を使用します。ここで
は、私がこれまで(残りはテスト目的であり、問題の唯一の機能はCreateIfNotExist()関数であることに注意してください)したものである:
#include <memory>
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
struct A {
A(int a) : x(a) {}
int x;
};
struct B {
B() : test(nullptr) {}
void CreateIfNotExist(int val) {
std::shared_ptr<A> newPtr = std::make_shared<A>(val);
std::shared_ptr<A> _null = nullptr;
std::atomic_compare_exchange_strong(&test, &_null, newPtr);
}
std::shared_ptr<A> test;
};
int gRet = -1;
std::mutex m;
void Func(B* b, int val) {
b->CreateIfNotExist(val);
int ret = b->test->x;
if(gRet == -1) {
std::unique_lock<std::mutex> l(m);
if(gRet == -1) {
gRet = ret;
}
}
if(ret != gRet) {
std::cout << " FAILED " << std::endl;
}
}
int main() {
B b;
std::vector<std::thread> threads;
for(int i = 0; i < 10000; ++i) {
threads.clear();
for(int i = 0; i < 8; ++i) threads.emplace_back(&Func, &b, i);
for(int i = 0; i < 8; ++i) threads[i].join();
}
}
が、これは、これを行うための正しい方法は何ですか? CreateIfNotExist()を同時に呼び出すすべてのスレッドがすべて同じshared_ptrを使用するようにするには、より良い方法がありますか?おそらく、これらの線に沿って
test'が有効である必要があり、 'ので、 'B'がcontructableデフォルトではないことはありませなぜ? – NathanOliver
ただ1つの共有ポインタを定義し、それをスポーンするごとに各スレッドに渡します。 – sji
@ sji私は、私のユースケースに合うような方法でコードを意図的に構造化しましたが、多くのリファクタリングがなければそれはできません。 – Andrew