Bクラスがインスタンス化され、複数のスレッドによって使用される、次の C++11 コードを検討してください。共有ベクトルを変更するためB、 の ctor およびメンバー関数 foo でアクセスをロックする必要がありBます。メンバー変数を初期化するidには、複数のスレッドからアクセスするため、アトミック変数であるカウンターを使用します。
struct A {
A(size_t id, std::string const& sig) : id{id}, signature{sig} {}
private:
size_t id;
std::string signature;
};
namespace N {
std::atomic<size_t> counter{0};
typedef std::vector<A> As;
std::vector<As> sharedResource;
std::mutex barrier;
struct B {
B() : id(++counter) {
std::lock_guard<std::mutex> lock(barrier);
sharedResource.push_back(As{});
sharedResource[id].push_back(A("B()", id));
}
void foo() {
std::lock_guard<std::mutex> lock(barrier);
sharedResource[id].push_back(A("foo()", id));
}
private:
const size_t id;
};
}
残念ながら、このコードには競合状態が含まれており、このようには機能しません (ctor と foo() が同じ ID を使用しない場合があります)。id の初期化をミューテックスによってロックされている ctor 本体に移動すると、次のように動作します。
struct B {
B() {
std::lock_guard<std::mutex> lock(barrier);
id = ++counter; // counter does not have to be an atomic variable and id cannot be const anymore
sharedResource.push_back(As{});
sharedResource[id].push_back(A("B()", id));
}
};
後者の例が機能する理由を理解するのを手伝ってもらえますか (同じミューテックスを使用していないためですか?)? ctorの本体でロックせずidに、イニシャライザリストで初期化する安全な方法はありますか? B私の要件は、そうでidなければならずconst、の初期化がid初期化子リストで行われることです。