ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

oneapi::tbb::concurrent_multimap 观察者成员详解:get_allocator、key_comp 与 value_comp

oneapi::tbb::concurrent_multimap 观察者成员详解:get_allocator、key_comp 与 value_comp oneapi::tbb::concurrent_multimap 观察者成员详解get_allocator、key_comp 与 value_comp【免费下载链接】moldmold: A Modern Linker 项目地址: https://gitcode.com/GitHub_Trending/mo/moldoneapi::tbb::concurrent_multimap是 oneAPI Threading Building BlocksoneTBB提供的并发有序关联容器支持并发插入、查找与遍历并允许存储多个相等键的元素。本文以 oneTBB 规范文档中的 Observers观察者章节为核心深入剖析容器对外暴露的三个只读观察接口——get_allocator()、key_comp()与value_comp()并结合仓库内实际头文件实现与一致性测试帮助读者理解其语义、底层机制及典型使用场景从而更准确地驾驭这个并发容器。Observers 章节在规范文档中的位置在 oneTBB 规范文档中concurrent_multimap的接口被组织为若干子章节分别描述构造与析构、迭代器、查找、容量、安全/非安全修改、并行遍历、推导指引以及非成员函数等。Observers 是其中专门存放只读观察接口的一节位于 observers.rst与 value_compare_cls.rst 相配合共同定义了容器对外暴露的三个观察者函数。在主类 synopsisconcurrent_multimap_cls.rst中这三个函数被集中声明在// Observers注释之下allocator_type get_allocator() const; key_compare key_comp() const; value_compare value_comp() const;它们共同的特点是不修改容器状态仅用于向调用方查询容器的内部配置对象分配器、键比较器及其派生的值比较器是标准库容器接口在并发容器上的直接对应。get_allocator()获取关联的分配器接口签名与语义allocator_type get_allocator() const;Returns返回与*this关联的分配器allocator的一份拷贝。该接口的意义在于容器内部为节点分配内存所使用的分配器与调用方在构造容器时传入的分配器保持一致性调用方可以通过该函数取回这份分配器以便使用相同的内存分配策略创建其他容器或进行内存相关操作。底层实现concurrent_multimap本身并未直接定义该成员而是通过继承复用基类实现。从 concurrent_map.h 可以看到template typename Key, typename Value, typename Compare std::lessKey, typename Allocator tbb::tbb_allocatorstd::pairconst Key, Value class concurrent_multimap : public concurrent_skip_list map_traitsKey, Value, Compare, geometric_level_generator32, Allocator, true { ... };concurrent_multimap继承自内部实现concurrent_skip_list跳表并通过map_traits将Allocator传递下去。get_allocator()的实际实现在 _concurrent_skip_list.h 中allocator_type get_allocator() const { return my_node_allocator; }它直接返回内部成员my_node_allocator的拷贝。该成员在容器构造时由用户传入的分配器初始化默认参数为tbb::tbb_allocatorstd::pairconst Key, Value并实际用于跳表节点的分配与释放。值得注意的是concurrent_skip_list还通过node_allocator_traits处理分配器的传播语义例如在拷贝构造时使用select_on_container_copy_construction决定新容器的分配器见 _concurrent_skip_list.h并在swap时根据propagate_on_container_swap与is_always_equal决定是否交换分配器。因此调用get_allocator()获得的分配器正是容器节点实际使用的那个分配器。key_comp()获取键比较函数对象接口签名与语义key_compare key_comp() const;Returns返回与*this关联的键比较函数对象key comparison functor的一份拷贝。key_compare是容器模板的第二模板参数Compare默认std::lessKey的类型别名负责定义容器中键的全序关系。整个跳表的有序性、查找路径、equal_range结果以及迭代器的遍历顺序都建立在该比较器之上。底层实现同样在 _concurrent_skip_list.h 中key_compare key_comp() const { return my_compare; }实现直接返回内部成员my_compare的拷贝。这个比较器成员声明于 _concurrent_skip_list.h在容器构造时保存并贯穿于跳表的所有比较操作。需要说明的是规范文档concurrent_multimap_cls.rst与源码将key_compare直接定义为模板参数Compare即using key_compare Compare;。当Compare满足透明比较器transparent comparator即定义is_transparent类型时容器还支持异质键查找heterogeneous lookup相关特性在源码中以is_transparent dependent_boolcomp_is_transparentkey_compare, T的形式体现见 _concurrent_skip_list.h。value_comp()获取值比较函数对象接口签名与语义value_compare value_comp() const;Returns返回一个用于比较value_type对象的value_compare类对象。value_type即std::pairconst Key, T。与key_comp()返回底层键比较器不同value_comp()返回的是一个适配层对象它把比较两个键的语义包装成比较两个pair的语义。value_compare 类的完整剖析value_compare的完整定义由独立章节 value_compare_cls.rst 给出其类 synopsis 如下namespace oneapi { namespace tbb { template typename Key, typename T, typename Compare, typename Allocator class concurrent_multimapKey, T, Compare, Allocator::value_compare { protected: key_compare comp; value_compare( key_compare c ); public: bool operator()( const value_type lhs, const value_type rhs ) const; }; } }该嵌套类包含一个受保护成员key_compare comp保存键比较函数对象、一个受保护构造函数接受key_compare以及一个公开的operator()(const value_type, const value_type)。operator()的语义是通过调用存储的键比较函数comp来比较lhs.first与rhs.first。即返回true当且仅当lhs.first与rhs.first按键比较器判定相等comp(lhs.first, rhs.first)成立。源码中的对应实现在 concurrent_map.h 的map_traits中可以看到该嵌套类的实际实现class value_compare { public: bool operator()(const value_type lhs, const value_type rhs) const { return comp(lhs.first, rhs.first); } protected: value_compare(compare_type c) : comp(c) {} friend struct map_traits; compare_type comp; }; static value_compare value_comp(compare_type comp) { return value_compare(comp); }要点如下operator()只比较lhs.first与rhs.first完全忽略second即映射值这与std::multimap的value_compare语义一致构造函数是protected的map_traits被声明为friend因此用户无法直接构造value_compare对象只能通过容器的value_comp()成员获取map_traits提供静态工厂value_comp(compare_type)供基类构造value_compare使用。基类concurrent_skip_list中的value_comp()实现正是调用该工厂value_compare value_comp() const { return container_traits::value_comp(my_compare); }见 _concurrent_skip_list.h这意味着每次调用value_comp()都会基于当前容器的my_compare现场构造一个新的value_compare对象——它并不持有独立状态而是底层key_compare的一个视图适配。三个观察者的关系与实战示例get_allocator()、key_comp()、value_comp()三者之间呈现清晰的层次关系观察者返回类型返回内容底层来源get_allocator()allocator_type节点分配器拷贝my_node_allocatorkey_comp()key_compare即Compare键比较器拷贝my_comparevalue_comp()value_compare基于my_compare构造的值比较器container_traits::value_comp(my_compare)key_comp()与value_comp()的区别在于比较对象类型前者比较两个Key后者比较两个value_typepair且后者仅使用 pair 的第一个分量。下面是一个基于仓库类型定义concurrent_map.h的完整使用示例展示三个观察者的典型调用方式#include oneapi/tbb/concurrent_map.h #include cassert using mmap_t oneapi::tbb::concurrent_multimapint, std::string; int main() { mmap_t m; // Compare 默认为 std::lessint m.emplace(1, one); m.emplace(1, uno); // concurrent_multimap 允许多个相等键 m.emplace(3, three); // 1) 获取分配器拷贝默认是 tbb_allocatorstd::pairconst int, std::string mmap_t::allocator_type alloc m.get_allocator(); // 2) 获取键比较器可直接用于 std::sort 等算法 mmap_t::key_compare comp m.key_comp(); assert(comp(1, 2)); // std::lessint 语义 // 3) 获取值比较器比较对象是 value_typepair mmap_t::value_compare vcomp m.value_comp(); mmap_t::value_type a{1, one}; mmap_t::value_type b{2, two}; assert(vcomp(a, b)); // 仅比较 a.first 与 b.first return 0; }注意value_compare的构造函数是受保护的见 concurrent_map.h用户代码无法直接创建value_compare对象只能通过m.value_comp()获取这正是规范文档将其构造函数标记为protected的原因。自定义比较器场景当用户传入自定义比较器时三个观察者的返回内容会随之变化。例如构造concurrent_multimapint, int, std::greaterint后key_comp()返回std::greaterint的拷贝value_comp()返回的value_compare内部则保存该std::greaterint其operator()通过它比较两个 pair 的键分量using gmmap_t oneapi::tbb::concurrent_multimapint, int, std::greaterint; gmmap_t gm; gmmap_t::value_compare gvc gm.value_comp(); // gvc({2, 0}, {1, 0}) 返回 true因为 2 1 按 std::greater 判定源码与测试佐证这三个观察者并非孤立接口它们与容器的其余部分共享同一套状态并有专门的测试覆盖。仓库中的一致性测试文件 conformance_concurrent_map.cpp 将concurrent_map与concurrent_multimap一并纳入测试测试注释明确标注[containers.concurrent_map containers.concurrent_multimap]规范条目并通过AllowMultimapping特性将concurrent_multimap与concurrent_map区分对待见该文件第 32-41 行。其中对容器成员类型member types的测试test_member_typesoneapi::tbb::concurrent_multimap()即覆盖了allocator_type、key_compare、value_compare等类型的正确性间接验证了观察者接口所依赖的类型体系。此外concurrent_multimap与concurrent_map共享同一套跳表基类唯一区别在于map_traits的allow_multimapping模板参数concurrent_map为false保证键唯一concurrent_multimap为true允许多个相等键见 concurrent_map.h。因此本文讨论的三个观察者同样适用于concurrent_map其语义在两个容器上完全一致。使用注意事项只读语义三个观察者均不修改容器可在任意时刻安全调用但规范文档concurrent_multimap_cls.rst明确指出该容器支持并发插入、查找与遍历但不支持并发删除观察者查询应与其他并发访问规则一并遵守拷贝语义get_allocator()与key_comp()返回的是内部对象的一份拷贝而非引用若比较器或分配器内部持有可变状态罕见但合法调用方拿到的是拷贝不会反向影响容器与标准库的一致性value_comp()仅比较 pair 的第一分量键与std::multimap的行为一致可用于把并发容器与标准算法对接异质查找若Compare定义有is_transparent类型key_comp()返回的比较器还可用于透明比较上下文中容器也相应提供异质的find、equal_range重载见 _concurrent_skip_list.h。通过理解这三个观察者开发者可以完整掌握concurrent_multimap的配置查询能力分配器决定了节点的内存来源键比较器决定了容器的排序与查找语义而值比较器则是键比较器在value_type维度上的投影——三者共同构成了容器对外部世界的自我描述接口。【免费下载链接】moldmold: A Modern Linker 项目地址: https://gitcode.com/GitHub_Trending/mo/mold创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表