c++ - 在处理加载程序线程和大量数据时扩展关键部分的放置位置
问题描述
我已经阅读了有关该主题的教程并观看了有关它的 YouTube 视频,我想我理解为什么使用它们的原因。使用它们的原因有很多,但其中之一是因为现代多核 CPU 具有内部缓存以提高性能(L1 和 L2)。如果一个核心在与该核心关联的缓存中存储了旧内存,这可能会导致一个核心读取旧信息。添加临界区会强制刷新这些缓存。
我试图增加我对这个关键部分必须放在哪里的理解,我觉得大多数在线信息源实际上都无法很好地解释。这就是为什么我在这里问你们专业人士!:)
给你一个简短的例子:
#include <iostream>
#include <thread>
#include <mutex>
#include <list>
static constexpr auto OneMegabyte = 1 * 1024 * 1024;
struct Result
{
char data[OneMegabyte];
};
std::mutex mutex;
std::list<Result*> results;
void write_lots_of_data(Result* result)
{
auto f = fopen("large_file.txt", "rb");
fread(result->data, OneMegabyte, 1, f);
fclose(f);
}
void read_lots_of_data(Result* result)
{
//
}
void thread()
{
auto result = new Result();
// Writes one megabyte of data from somewhere into Memory::values
write_lots_of_data(result);
std::lock_guard<std::mutex> l(mutex);
results.push_back(result);
}
int main(int argc, char** argv)
{
std::thread t(&thread);
while (true)
{
std::lock_guard<std::mutex> l(mutex);
if (results.empty())
continue;
auto first_result = results.begin();
read_lots_of_data(*first_result);
results.erase(first_result);
break;
}
return 0;
}
访问results
受到保护,不会同时被读取和写入 - 我明白这一点。但是放入results
列表的实际内存呢?为了安全起见,我是否必须将关键部分放在write_lots_of_data
方法之前,还是足以安全地保护results
列表?
解决方案
你的代码是正确的。
互斥锁保护列表,而不是列表节点中包含的数据。因此,正如您所写,将数据填充到 Result 结构中是不受保护的,不需要保护。
阅读时,只有列表需要保护。结果的读数不需要保护。您的代码应该按照编写的方式工作。它可以通过一种方式进行改进:
Result* get_result()
{
std::lock_guard<std::mutex> l(mutex);
if (not results.empty())
{
Result* first_result = results.front();
results.pop_front();
return first_result;
}
return nullptr;
}
int main(int argc, char** argv)
{
std::thread t(&thread);
while (true)
{
Result* first_result = get_result();
if (first_result)
{
read_lots_of_data(first_result);
delete first_result;
}
}
return 0;
}
将锁限制为仅在列表上操作将有助于提高性能和可读性。读者会意识到只有列表被锁定,而不是结果的读取操作。
在你走得太远之前,请考虑std::unique_ptr<Result>
在你的代码中使用 as well 而不是 new/delete。
推荐阅读
- facebook-login - 如何修复错误Facebook登录导致android
- java - 如何以编程方式将静态 html 页面部署到 heroku?
- c++ - 如何将接口对象传递给方法?
- javascript - 选择日期时,数据选择器模块未关闭
- reactjs - 如何在反应中使用回调函数消除setState中的滞后
- string - 将字符串转换为字节并在 Lua 中写入文件
- vue.js - 在 Vue 中创建条件输入字段组件
- c# - EF Core.Tools 未被识别为 cmdlet、函数或程序的名称
- google-pay - Google Pay 如何判断用户的付款方式?
- javascript - 附加的行组作为 jquery 响应不尊重表条带表样式