如何解决C++:多线程时访问类数据成员的混淆
我有以下最小工作示例,其中我在向量 markov_chain
中创建了多个 chains
对象,并在向量 thread
中创建了相同数量的 workers
对象,每个都在每个对应的 markov_chain
对象上执行一个 sample
类成员函数 markov_chain
。此函数采用一些整数(在下面的示例中为 99)并将其分配给 acceptance
对象的 markov_chain
公共数据成员。然后我为向量中的每个对象打印 acceptance
的值。
#include <iostream>
#include <thread>
#include <algorithm>
#include <vector>
class markov_chain
{
public:
unsigned int length{0},acceptance{0};
markov_chain(unsigned int l) {length=l;}
~markov_chain() {}
void sample(int acc);
};
void markov_chain::sample(int acc)
{
acceptance = acc;
std::cout << length << ' ' << acceptance << std::endl;
}
int main()
{
int number_of_threads{3};
int number_of_samples{1000};
std::vector<markov_chain> chains;
std::vector<std::thread> workers;
for (int i = 0; i <= number_of_threads; i++) {
chains.push_back(markov_chain(number_of_samples));
workers.push_back(std::thread(&markov_chain::sample,chains[i],99));
}
std::for_each(workers.begin(),workers.end(),[](std::thread &t)
{
t.join();
});
for (int i = 0; i <= number_of_threads; i++) {
std::cout << chains[i].length << ' ' << chains[i].acceptance << std::endl;
}
return 0;
}
执行后,程序输出
1000 99
1000 99
1000 99
1000 99
1000 0
1000 0
1000 0
1000 0
因此程序未能为向量 acceptance
中的对象更改 chains
的值。我不知道为什么会这样;当我在不创建线程的情况下使用函数 sample
时,它成功地分配了所需的值。
解决方法
您的代码有两个问题:
-
在创建每个
std::thread
时,您将每个对象的副本作为this
的sample()
参数传递。 -
以您正在执行的方式将多个对象推入
chains
向量可能会导致该向量重新分配其内部数组,从而使您已经传递给现有线程的任何对象指针无效,因为那些原始对象现在在重新分配后消失了。
在创建任何线程之前,您需要完全初始化 chains
向量。并且您需要将指针传递给每个线程的每个对象。
您可以预先reserve()
数组以避免在推入数组时重新分配,例如:
int main()
{
int number_of_threads{3};
int number_of_samples{1000};
std::vector<markov_chain> chains;
std::vector<std::thread> workers;
chains.reserve(number_of_threads);
for (int i = 0; i < number_of_threads; ++i) {
chains.push_back(markov_chain(number_of_samples));
workers.push_back(std::thread(&markov_chain::sample,&chains[i],99));
}
for(auto &t : workers) {
t.join();
}
for (auto &c : chains) {
std::cout << c.length << ' ' << c.acceptance << std::endl;
}
return 0;
}
但是,由于所有对象都使用相同的起始值进行初始化,因此更简单的方法是完全去掉 chains.push_back()
并使用 chains.resize()
代替,例如:
int main()
{
int number_of_threads{3};
int number_of_samples{1000};
std::vector<markov_chain> chains;
std::vector<std::thread> workers;
chains.resize(number_of_threads,markov_chain(number_of_samples));
for (int i = 0; i < number_of_threads; ++i) {
workers.push_back(std::thread(&markov_chain::sample,99));
}
for(auto &t : workers) {
t.join();
}
for (auto &c : chains) {
std::cout << c.length << ' ' << c.acceptance << std::endl;
}
return 0;
}
或者,甚至使用 vector
构造函数本身:
int main()
{
int number_of_threads{3};
int number_of_samples{1000};
std::vector<markov_chain> chains(number_of_threads,markov_chain(number_of_samples));
std::vector<std::thread> workers;
for (int i = 0; i < number_of_threads; ++i) {
workers.push_back(std::thread(&markov_chain::sample,99));
}
for(auto &t : workers) {
t.join();
}
for (auto &c : chains) {
std::cout << c.length << ' ' << c.acceptance << std::endl;
}
return 0;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。