c++ - cpp:如何使类中的向量访问线程安全?
问题描述
我昨天在类似的方向上发布了一些东西,但这个问题专门关于互斥锁,我在引用的“重复”线程中没有找到太多答案。我现在想尝试更一般地问,我希望没关系。
看看这段代码:
#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 数组(感觉很糟糕,因为我需要能够将数据容器添加到数据存储区,所以这意味着每次更改数据存储区的大小时都要清除数组并重建它?),或者
- 使对向量的访问成为原子的(作为一种想法,这使我的操作成为我想要的线程安全的,但是向量没有原子不变量,或者在某些非 STL-lib 中存在?),或者
- 为数据类中的互斥体编写一个包装器?
对于我的项目而言,哪个线程首先访问并不重要,重要的是我可以通过一个线程将整个向量明确读/写到数据元组中,而无需另一个线程同时操作数据集。
解决方案
我相信我现在参考 Sam 的评论做了这件事,而且它似乎有效,这是正确的吗?
#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,我应该在移动实例时不会留下内存泄漏,对吧?
推荐阅读
- r - 从 B3 iFrame 抓取网页
- python - 在第二次出现列值后删除所有行
- r - R中的模拟概率谜题
- tsql - 带有 MAX() 的标量值 UDF 无法将数据返回给客户端
- python - 如何使用 Python 在 Excel 电子表格中绘制形状?
- ms-access - FROM 子句中的运行时错误 3131 语法错误 - Microsoft 访问
- python - 从 django 视图上下文字典中传递数据以响应组件
- python - 如何从python中的文本文件中删除重复的单词
- git - (已解决)尝试连接到 GitHub 时,SSH 和 HTTPS 密钥对我的 Eclipse 不起作用
- angular-universal - 禁用 NGUniversal Routes 和 bootstrap.min.css.map?