考慮以下C++ 11代碼,其中類B
被實例化並被多個線程使用。因爲B
修改了一個共享向量,所以我必須鎖定它在ctor和B
的成員函數foo中的訪問權限。要初始化成員變量id
我使用計數器是一個原子變量,因爲我從多個線程訪問它。C++中原子變量的線程安全初始化
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;
};
}
不幸的是,這個代碼包含一個競爭條件和這樣不工作(有時在構造函數和Foo()不使用相同的ID)。如果我移動ID的初始化是由一個互斥鎖的構造函數體,它的工作原理:
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));
}
};
能否請你幫我理解爲什麼後者的例子作品(是不是因爲它不使用相同的互斥?)?有沒有一種安全的方式來初始化id
的初始化程序列表B
而不鎖定在ctor的主體中?我的要求是,id
必須是const
並且id
的初始化發生在初始化程序列表中。
你能發佈導致問題的實際代碼嗎?你提出的代碼沒有意義(至少在缺少'A'的定義的情況下)。例如,你不能簡單地訪問'sharedResource [id]',而實際上沒有做一些事情來調整'sharedResource'來包含'id + 1'元素。除非'A'包含成員函數'push_back',否則代碼甚至不應該編譯。 – 2012-04-04 18:51:43
@JamesKanze爲什麼'A'需要'push_back'成員?我只看到一個'(const char *,size_t)'構造函數和一個正在使用的移動/拷貝構造函數。 OP:如果可能,請將其設爲[SSCCE](http://sscce.org) – je4d 2012-04-04 19:57:51
@ je4d:'sharedResource'是'std :: vector ',所以'sharedResource [id]'返回'A&'和'sharedResource [id] .push_back(...)'因此調用'A :: push_back'。 – ildjarn 2012-04-04 19:59:31