首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >cpp:如何使向量在类中的访问是线程安全的?

cpp:如何使向量在类中的访问是线程安全的?
EN

Stack Overflow用户
提问于 2020-04-09 22:38:20
回答 1查看 55关注 0票数 0

我昨天在一个类似的方向上发布了一些东西,但这个问题特别是关于互斥的,我在引用的"duplicate“帖子中没有找到太多答案。我现在想问得更笼统一些,希望没问题。

看看这段代码:

代码语言:javascript
复制
#include <iostream>
#include <mutex>
#include <vector>
#include <initializer_list>
using namespace std;

class Data {
public:

    void write_data(vector<float>& data) {
        datav = move(data);
    }

    vector<float>* read_data() {
        return(&datav);
    }

    Data(vector<float> in) : datav{ in } {};

private:
    vector<float> datav{};
};

void f1(vector<Data>& in) {
    for (Data& tupel : in) {
        vector<float>& in{ *(tupel.read_data()) };
        for (float& f : in) {
            f += (float)1.0;
        };
    };
}

void f2(vector<Data>& in) {
    for (Data& tupel : in) {
        vector<float>& in{ *(tupel.read_data()) };
        for (float& f : in) {
            cout << f << ",";
        };
    };
}
int main() {
    vector<Data> datastore{};
    datastore.emplace_back(initializer_list<float>{ 0.2, 0.4 });
    datastore.emplace_back(initializer_list<float>{ 0.6, 0.8 });
    vector<float> bigfv(50, 0.3);
    Data demo{ bigfv };
    datastore.push_back(demo);
    thread t1(f1, ref(datastore));
    thread t2(f2, ref(datastore));
    t1.join();
    t2.join();
};

在我的预期中,我会猜到我会得到输出值的混合,这取决于哪个线程首先得到向量值,所以在第三个50x0.3f的“演示”向量中,我会预期输出是0.3 (t2首先获得)和1.3 (t1首先获得)的混合。即使我试图使用尽可能多的按引用传递、直接指针等来避免复制(原始项目使用了相当大的数据量),代码的行为仍然是已定义的(总是t2,然后是t1访问)。为什么?难道我不是在两个线程函数中通过引用直接访问浮点数吗?

您将如何使这种向量访问定义良好?我在另一个线程中找到的唯一可能的解决方案是:

将类似大小的unique_ptr数组添加到互斥锁(感觉很糟糕,因为我需要能够将数据容器添加到数据存储中,因此这意味着每次更改数据存储的大小时都要清除该数组并重新构建它?),或者

-make访问向量原子(这使得我的操作就像我想要的线程安全,但向量没有原子不变量,或者是否存在于某些非STL-lib中?),或者

在数据类中为互斥锁-write包装器?

对于我的项目来说,哪个线程先访问并不重要,重要的是我可以定义一个线程将整个向量读/写到数据管道中,而不需要另一个线程同时操作数据集。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-04-10 16:08:43

我相信我现在参考了Sam的评论,它似乎起作用了,这是正确的吗?

代码语言:javascript
复制
#include <iostream>
#include <mutex>
#include <vector>
#include <initializer_list>
using namespace std;

class Data {
public:
    unique_ptr<mutex> lockptr{ new mutex };
    void write_data(vector<float>& data) {
        datav = move(data);
    }

    vector<float>* read_data() {
        return(&datav);
    }

    Data(vector<float> in) : datav{ in } {
    };
    Data(const Data&) = delete;
    Data& operator=(const Data&) = delete;
    Data(Data&& old) {
        datav = move(old.datav);
        unique_ptr<mutex> lockptr{ new mutex };
    }
    Data& operator=(Data&& old) {
        datav = move(old.datav);
        unique_ptr<mutex> lockptr{ new mutex };
    }
private:
    vector<float> datav{};
    //mutex lock{};

};

void f1(vector<Data>& in) {
    for (Data& tupel : in) {
        unique_lock<mutex> lock(*(tupel.lockptr));
        vector<float>& in{ *(tupel.read_data()) };
        for (float& f : in) {
            f += (float)1.0;
        };
    };
}

void f2(vector<Data>& in) {
    for (Data& tupel : in) {
        (*(tupel.lockptr)).try_lock();
        vector<float>& in{ *(tupel.read_data()) };
        for (float& f : in) {
            cout << f << ",";
        };
        (*(tupel.lockptr)).unlock();
    };
}
int main() {
    vector<Data> datastore{};
    datastore.emplace_back(initializer_list<float>{ 0.2, 0.4 });
    datastore.emplace_back(initializer_list<float>{ 0.6, 0.8 });
    vector<float> bigfv(50, 0.3);
    Data demo{ bigfv };
    datastore.push_back(move(demo));
    thread t1(f1, ref(datastore));
    thread t2(f2, ref(datastore));
    t1.join();
    t2.join();
};

通过使用unique_ptr,我应该在移动实例时不会留下内存泄漏,对吧?

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

https://stackoverflow.com/questions/61123695

复制
相关文章

相似问题

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