B
并被多个线程使用。 因为B
修改了共享向量,所以我必须在B
的构造函数和成员函数foo中锁定对它的访问。 为了初始化成员变量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));
}
};
您能帮助我理解为什么后面的例子起作用吗(是因为它没有使用相同的互斥量吗?)?在B
的初始化程序列表中安全地初始化id
,而不必在构造函数主体中锁定它,是否有方法?我的要求是 id
必须是const
并且id
的初始化必须在初始化程序列表中进行。
A
的情况下)。例如,您不能仅仅访问sharedResource[id]
,而未实际执行任何操作来调整sharedResource
的大小以包含id + 1
个元素。除非A
包含一个名为push_back
的成员函数,否则该代码甚至不应编译。 - James KanzeA
需要一个push_back
成员函数?我只看到使用了一个(const char*,size_t)
构造函数和一个移动/复制构造函数。 OP:如果可能,请将其制作成 SSCCE。 - je4dsharedResource
是一个std::vector<A>
,所以sharedResource[id]
返回一个A&
,因此sharedResource[id].push_back(...)
调用的是A::push_back
。 - ildjarnA
,所以它不会被推入到另一个A
中,因为这对于push_back
的传统语义来说没有多少意义。我猜测代码并不是 OP 实际想要编写的。 - je4d