- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我正在尝试实现一个线程安全的无锁容器,类似于 std::vector,根据这个 https://software.intel.com/en-us/blogs/2008/07/24/tbbconcurrent_vector-secrets-of-memory-organization
据我了解,为了防止重新分配并使所有线程上的所有迭代器无效,它们添加了新的连续 block ,而不是单个连续数组。
他们添加的每个 block 的大小都是 2 的递增幂,因此他们可以使用 log(index) 来找到应该在 [index] 处的项目所在的正确段。
据我所知,他们有一个指向段的静态指针数组,所以他们可以快速访问它们,但是他们不知道用户想要多少段,所以他们做了一个小的初始段,如果数量段超过当前计数,它们分配一个巨大的并切换到使用那个。
问题是,添加新段不能以无锁线程安全的方式完成,或者至少我还没弄清楚怎么做。我可以自动增加当前大小,但仅此而已。
而且从小段指针数组切换到大段指针数组还涉及大量分配和内存拷贝,所以我无法理解他们是如何做到的。
他们在网上发布了一些代码,但是所有重要的功能都没有可用的源代码,它们在他们的线程构建 block DLL 中。下面是一些演示该问题的代码:
template<typename T>
class concurrent_vector
{
private:
int size = 0;
int lastSegmentIndex = 0;
union
{
T* segmentsSmall[3];
T** segmentsLarge;
};
void switch_to_large()
{
//Bunch of allocations, creates a T* segmentsLarge[32] basically and reassigns all old entries into it
}
public:
concurrent_vector()
{
//The initial array is contiguous just for the sake of cache optimization
T* initialContiguousBlock = new T[2 + 4 + 8]; //2^1 + 2^2 + 2^3
segmentsSmall[0] = initialContiguousBlock;
segmentsSmall[1] = initialContiguousBlock + 2;
segmentsSmall[2] = initialContiguousBlock + 2 + 4;
}
void push_back(T& item)
{
if(size > 2 + 4 + 8)
{
switch_to_large(); //This is the problem part, there is no possible way to make this thread-safe without a mutex lock. I don't understand how Intel does it. It includes a bunch of allocations and memory copies.
}
InterlockedIncrement(&size); //Ok, so size is atomically increased
//afterwards adds the item to the appropriate slot in the appropriate segment
}
};
最佳答案
我不会尝试将 segmentsLarge
和 segmentsSmall
合并。是的,这又浪费了一个指针。然后指针,我们称之为 segments
最初可以指向segmentsSmall。
另一方面,其他方法总是可以使用相同的指针,这使得它们更简单。
而从小到大的切换可以通过指针的一次比较交换来完成。
我不确定如何通过 union 安全地完成这项工作。
这个想法看起来像这样(请注意,我使用的是英特尔库早于的 C++11,因此他们可能使用其原子内在函数来实现它)。这可能会遗漏很多细节,我相信英特尔人员已经考虑了更多,因此您可能必须对照所有其他方法的实现来检查这一点。
#include <atomic>
#include <array>
#include <cstddef>
#include <climits>
template<typename T>
class concurrent_vector
{
private:
std::atomic<size_t> size;
std::atomic<T**> segments;
std::array<T*, 3> segmentsSmall;
unsigned lastSegmentIndex = 0;
void switch_to_large()
{
T** segmentsOld = segments;
if( segmentsOld == segmentsSmall.data()) {
// not yet switched
T** segmentsLarge = new T*[sizeof(size_t) * CHAR_BIT];
// note that we leave the original segment allocations alone and just copy the pointers
std::copy(segmentsSmall.begin(), segmentsSmall.end(), segmentsLarge);
for(unsigned i = segmentsSmall.size(); i < numSegments; ++i) {
segmentsLarge[i] = nullptr;
}
// now both the old and the new segments array are valid
if( segments.compare_exchange_strong(segmentsOld, segmentsLarge)) {
// success!
return;
} else {
// already switched, just clean up
delete[] segmentsLarge;
}
}
}
public:
concurrent_vector() : size(0), segments(segmentsSmall.data())
{
//The initial array is contiguous just for the sake of cache optimization
T* initialContiguousBlock = new T[2 + 4 + 8]; //2^1 + 2^2 + 2^3
segmentsSmall[0] = initialContiguousBlock;
segmentsSmall[1] = initialContiguousBlock + 2;
segmentsSmall[2] = initialContiguousBlock + 2 + 4;
}
void push_back(T& item)
{
if(size > 2 + 4 + 8) {
switch_to_large();
}
// here we may have to allocate more segments atomically
++size;
//afterwards adds the item to the appropriate slot in the appropriate segment
}
};
关于c++ - 根据intel博客实现concurrent_vector,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46761881/
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 7 年前。 Improve this ques
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我基本上有三个环境用于在我的主站点上工作。我的计算机上有我的本地一个,而我的网络服务器上有开发和实时的。我在本地环境中使用 Wordpress 开发了该站点,并希望通过 svn 使所有内容保持最新。
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 5年前关闭。 Improve thi
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我有 gatsby 博客,在我创建新帖子并构建静态文件后,将它们上传到我的主机上,每个用户都必须在我的博客上进行硬刷新才能看到更改。 上传新版本后如何在下次访问时自动刷新? 最佳答案 这种行为的另一个
我需要博客链接,以及涵盖 GroovyFx 的教程。我试过在谷歌上搜索它,我没有得到任何有用的教程。我需要从上到下全面覆盖 GroovyFx! 提前致谢。 最佳答案 您的意思是您想要全面覆盖的博客条目
我最近更换了计算机,并且不小心删除了所有源(Markdown 文件等)的本地版本。不管我怎么想,这一切都在 Github(我使用 GitHub 页面)中,所以我可以从那里开始。但是,我已经进入 Git
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
标题几乎说明了一切。博客在同一个帐户下。 Asked this question on Quora几乎没有回应。 我正在寻找一个网络应用程序,它可以自动执行该过程。如果那里还没有任何东西,我准备使用
在浏览一些关于 Java 反射和泛型的 Jakov Jenkov 博客时,我发现了以下段落: When runtime inspecting a parameterizable type itself
我进退两难:我已经做了rake deploy我的 Octopress 博客运行良好。文档说我必须再做 3 个步骤: git add . git commit -m 'message' git push
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 9 年前。 Improve this ques
我尝试了几种方法,但似乎无法完成其中的每一部分。我为某人制作了一个 wordpress 博客,她对此很满意,但最近想要更改标题。我把它放宽了,她想要它装箱/居中。基本上,标题包含 Logo 、导航和左
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我已经尝试在我的网络服务器上安装 Ghost.io 有一段时间了。我有一个带有 Centos 6 和 Cpanel 的 VPS。 今天我在 http://www.allaboutghost.com/o
这里我有一个网站,tinywolf.uk,我目前正在使用它。主页是一个独立于 wordpress 的静态网站,但网站的博客部分 http://www.tinywolf.uk/blog将由 wordpr
我是 Django Web 开发的半菜鸟。我已经成功添加了一个文件字段,实际上允许我将图像上传到帖子中(图像显示在帖子列表和帖子详细信息中),但是如果我想在帖子中添加多个图像该怎么办? 我目前正在撰写
我特别想了解 Web 开发和 Windows azure。我认为为个人网站创建一个博客应用程序将是一个很好且简单的项目来实现这一目标。 有谁知道演练/教程可以帮助我走上这条路,或者更好地涵盖这个确切的
我遇到了一个小问题,因为我目前正在尝试以编程方式同时登录两个 wordpress 博客。我有一个自定义登录页面,必须为两个 wordpress 博客创建 session 。一个博客工作得很好,但因为我
我是一名优秀的程序员,十分优秀!