- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我需要设计一个支持以下操作的数据结构:
我考虑使用列表在中间添加和删除元素。只有有限数量的间隔 - 所以可能使用 map 是不正确的。 STL 列表不支持这种访问方式(一个作者,多个读者)。 boost::intrusive::list 似乎是合适的。在侵入式列表之上,我将必须获取锁以读/写间隔。
此外,据我所知,与 STL 列表相比,侵入式列表可用于更好的缓存局部性(以及为包含的对象分配适当的内存)。
方法好吗?如果是,我也有兴趣了解您使用侵入式::列表的体验,尤其是对于多线程应用程序。
最佳答案
这里有 2 个不同的问题:
您的数据结构将为每次写入执行 (20-80) x (2-8) 次读取。
(1)。首先,假设您的范围是如下数据结构
struct Interval
{
Interval(int start, int length)
: m_start(start),
m_length(length)
{}
int m_start;
int m_length;
int value; // Or whatever
};
<p>Since reads massively outnumber writes, lookup needs to be fast, while modifications don't.</p>
<p>Using a list for your data structure means O(N) lookups and O(1) modification - exactly the wrong way around.</p>
<p>The simplest possible representation of your structure is a vector. If the intervals are held in sorted order, lookups are O(logN) and modifications are O(N).</p>
<p>To implement this, just add a comparator to Interval:</p>
<pre><code>bool operator<(const Interval& rhs) const
{
return m_start < rhs.m_start;
}
</code></pre>
<p>You can then use <code>std::lower_bound</code> to find the first interval equal or lower to your search interval in O(logN).</p>
<p>Next and previous interval are O(1) - decrement or increment the returned iterator.</p>
<p>Splitting an interval means inserting a new element after the current one and adjusting the length of the current - O(N).</p>
<p>Joining two intervals means adding the length of the next one to the current one and erasing the next one - O(N).</p>
<p>You should <code>reserve()</code> enough space in the vector for the maximum number of elements to minimise resizing overhead.</p>
<p>(2). Following Knuth, '<em>premature optimisation is the root of all evil</em>'.</p>
A single read/write lock on the structure holding your vector<Interval>
很可能就足够了。唯一可能的问题是 (2a) 由于读者独占锁而导致写入者饥饿,或 (2b) 由于写入者更新时间过长而导致读者饥饿。
(2a) 如果(且仅当)您面临写入饥饿,您可以使锁定更细化。不过,极有可能情况并非如此。为此:
让你的 vector 通过指针而不是值来保持它的间隔。这样调整大小就不会在内存中移动对象。让每个间隔包含一个读/写锁。
对于阅读:获取集合的读取锁,然后获取所需间隔的读取锁。如果不需要读取任何其他间隔,则在获得间隔锁后立即放弃集合锁,以允许其他线程继续进行。
如果您需要读取其他存储桶,您可以按任何顺序对它们进行读取锁定,直到您放弃集合读取锁定,此时写入器可以添加或删除您尚未锁定的任何间隔。获取这些锁时顺序无关紧要,因为当您持有集合上的读锁时,作者无法更改 vector ,并且读锁不会竞争。
对于写入:
获取集合的写锁,然后获取你想要的时间间隔。请注意,对于将添加或删除间隔的任何更新,您必须持有集合写锁。如果你只更新一个间隔,你可以放弃集合锁。否则,您需要持有写锁并在您将要修改的任何时间间隔内获取写锁。您可以按任何顺序获取间隔锁,因为没有集合锁,任何读者都无法获取新的读锁。
以上的工作原理是对 writer thread 更加自私,这应该会消除饥饿。
(2b) 如果您面临读者饥饿,这种情况更不可能发生,最好的解决方案是将集合的写入和读取分开。通过共享指针持有集合,并在其上有一个写锁。
对于阅读:获取写锁和 shared_ptr 的拷贝。放弃写锁。读者现在可以在没有任何锁定的情况下读取集合(它是不可变的)。
对于写入:按照读者的要求将 shared_ptr 带到集合中,放弃锁。制作该集合的私有(private)拷贝并对其进行修改(因为它是私有(private)拷贝,所以不需要锁定)。再次获取写锁并将现有的 shared_ptr 替换为您的新集合。完成旧集合的最后一个线程将销毁它。所有 future 的线程都将使用新更新的集合。
请注意,根据您的问题描述,此算法仅适用于一位作者。
关于c++ - 此多线程用例的最佳数据结构 : Is Intrusive List good?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/928827/
在入侵检测系统中,有两种技术称为异常检测和行为检测。我正在从头开始实现 IDS 并检查一些签名,并从某些站点将它们作为不同类型的检测方法提供。它们的基本区别是什么?在我看来,两者都是相同的,因此相同的
Boost.Intrusive可以在恒定时间内从Object-Ref或Object-Pointer中获得一个迭代器(请参见此处:https://www.boost.org/doc/libs/1_72_
虽然在boost::intrusive文档的Thread Safety段落中没有明确提到这种情况,但我想知道我是否可以考虑boost::intrusive::list::front() 安全时: 可能
是否可以直接从节点/元素获取下一个节点/元素?像这样: struct Data{ boost::intrusive::list_member_hook<> node; Data* get_
在boost.intrusive文档中,提到了使用多个容器存储在一个对象中。但是,没有实际的例子,所以我自己做了。这是正确的做法吗? #include struct tag1; class A:pu
我见过 intrusive 一词用来描述列表和堆栈等数据结构,但它是什么意思? 您能否给出一个侵入式数据结构的代码示例,以及它与非侵入式数据结构的区别? 另外,为什么要使其具有侵入性(或非侵入性)?有
在“何时使用?”一章的 Boost.Intrusive 文档中https://www.boost.org/doc/libs/1_72_0/doc/html/intrusive/usage_when.h
我有以下程序。我是在linux下用gcc-4.9.2搭建的。我的问题是: 1) 为什么哈希表第一次看起来是排序的,但是在从值中删除项目后排序就丢失了? 2) 我如何自己通过 key 遍历哈希表并说出
这是一条经常重复的建议,即不应从具有非虚拟析构函数的类继承(如果打算使用动态多态性)。这就是为什么从标准容器类继承被认为是一个坏主意。 另一方面,Boost.Intrusive 显式 states它的
如果我取消注释这些 //BaseList baselist; //MemberList memberlist; 在循环外并注释掉它崩溃的循环内的那些。我需要能够在任何循环之外拥有基本列表(和成员列
我不太明白为什么相同的元素可以出现在不同的侵入式容器中,同时保持性能和内存使用保证 boost::intrusive文档状态。 文档说: an intrusive container does not
我知道 boost 桶在内部是作为喜欢的列表实现的,对吗?至少根据http://www.boost.org/doc/libs/1_50_0/doc/html/unordered/buckets.htm
考虑这段编译成功的代码: #include using namespace boost::intrusive; typedef unordered_set_member_hook<> Hook; s
我希望使用侵入式 unordered_map。由于某种原因,库中只有一个 unordered_set。还有一个侵入式哈希表,但我不确定它是否具有相同的功能,也没有相同的接口(interface)。 我
我需要设计一个支持以下操作的数据结构: 搜索数据结构中的元素是基于一个区间的键。例如1-5区间内的值可能是3,6-11区间内的值可能是5等等。间隔是连续的,它们之间没有重叠。 查找上一个和下一个间隔
boost 文档 ( http://www.boost.org/doc/libs/1_55_0/doc/html/intrusive.html ) 指出侵入式容器是为 list 实现的(单链/双链),
我正在尝试从 boost::intrusive 集中分离元素并获得断言失败。 当我从容器中分离后删除元素时。 该类派生自 set_base_hook。 类 fileXfer:公共(public) se
我想知道是否有一种侵入性较小的方法来分析生产环境中正在运行的托管流程。 较少侵入性的意思: 附加调试器时没有执行延迟。 在获取运行线程等基本统计信息时不会延迟执行。 在Java世界中有这样一个工具部分
我有点惊讶的是,在学习 WPF/XAML/Silverlight 时,我遇到的几乎所有 XAML/C# 示例在 XAML 中都有“单击”事件,而在 Window 或 Page 构造函数中却很少。 由于
在两个boost::intrusive::slist>之间转移节点是否有效对象?类似下面的内容 auto one = boost::intrusive::slist>{}; auto two = bo
我是一名优秀的程序员,十分优秀!