首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++:在多线程时访问类数据成员的困惑

C++:在多线程时访问类数据成员的困惑
EN

Stack Overflow用户
提问于 2021-05-17 21:41:55
回答 1查看 48关注 0票数 0

我有下面的最小工作示例,其中我在向量chains中创建了许多chains对象,在向量workers中创建了相同数量的thread对象,每个对象在每个对应的markov_chain对象上执行一个markov_chain类成员函数sample。该函数接受一些整数(在下面的示例中为99),并将其分配给markov_chain对象的markov_chain公共数据成员。然后,为向量中的每个对象打印acceptance的值。

代码语言:javascript
复制
#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;
}

在执行时,程序输出

代码语言:javascript
复制
1000 99
1000 99
1000 99
1000 99
1000 0
1000 0
1000 0
1000 0

因此,程序未能为向量acceptance中的对象更改chains值。我不知道为什么会发生这种情况;函数sample在不创建线程的情况下成功地分配了所需的值。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-05-17 21:57:49

您的代码有两个问题:

  1. 在创建每个std::thread时,您将每个对象的一个副本作为sample()this参数传递。
  2. 以这样的方式将多个对象推入chains向量可能会导致向量重新分配其内部数组,从而使您已经传递给现有线程的任何对象指针无效,因为这些原始对象现在在重新分配之后消失了。

在创建任何线程之前,您需要完全初始化chains向量。您需要将指向每个对象的指针传递给每个线程。

您可以预先对数组进行reserve(),以避免在插入数组时重新分配,例如:

代码语言:javascript
复制
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(),例如:

代码语言:javascript
复制
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, &chains[i], 99));
    }

    for(auto &t : workers) {
        t.join();
    }

    for (auto &c : chains) {
        std::cout << c.length << ' ' << c.acceptance << std::endl;
    }

    return 0;
}

演示

或者,甚至使用vector构造函数本身:

代码语言:javascript
复制
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, &chains[i], 99));
    }

    for(auto &t : workers) {
        t.join();
    }

    for (auto &c : chains) {
        std::cout << c.length << ' ' << c.acceptance << std::endl;
    }

    return 0;
}

演示

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67577365

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档