英特尔® 线程构建模块 (Intel® TBB) 是最为人们熟知的一种 C++ 线程库,其最新的版本现已更新至 4.2。 与之前的 4.1 版本相比,更新后的版本提供了多个重要的新特性。 一些特性已经在 TBB 4.1 更新中发布出来。
新的同步基元 speculative_spin_mutex 提供了对推测锁定的支持。 这使得在第 4 代英特尔® 酷睿™ 处理器上使用英特尔(R) 事务性同步扩展 (Intel® TSX) 硬件特性成为可能。 只要不出现可能会产生不同于非推测性锁定的结果的“冲突”,推测互斥锁在支持硬件事务性内存 (如英特尔® TSX) 的处理器上工作时就会允许多个线程获取同一个锁。 因此在非竞争性案例中就不会发生串行化。 这样就能在“短”的关键区域上大幅提高性能和可扩展性。 如果不为事务性同步提供硬件支持,推测互斥锁的作用将与非推测互斥锁类似,同时很可能会表现出更差的性能。
英特尔 TBB 现在支持准确的异常传播特性(基于 C++11 exception_ptr)。 借助 exception_ptr,异常对象可以在线程之间安全地拷贝。 这为多线程环境中的异常处理提供了灵活性。 现在准确的异常传播在所有平台的预构建库中都已提供,例如: OS X*、Windows* 和 Linux*。 OS X* 上存在两种库: 第一个库与 gcc 标准库相关联 — 默认情况下该库不支持准确的异常传播。 为了使用该特性,您应当使用与 libc++ (Clang 中的 C++ 标准库) 相关联的第二种库。 为了使用这些特性,请先创建 Intel TBB 环境然后按照以下方式构建您的应用:
# tbbvars.sh libc++
# clang++ -stdlib=libc++ -std=c++11 concurrent_code.cpp -ltbb
除 concurrent_unordered_set和 concurrent_unordered_map容器之外,我们现在提供 concurrent_unordered_multiset和 concurrent_unordered_multimap,基于 Microsoft* PPL 原型。借助 concurrent_unordered_multiset,您可以多次插入一项,而这在 concurrent_unordered_set中是不可能实现的。 同样,concurrent_unordered_multimap允许您使用同一个键值插入一个以上的 <键,值>对。 就“多” 容器而言,find会在带有一个匹配搜索键的表格中返回第一项(或者 <键,值> 对)。
Intel TBB 容器现在可以使用 C++ 11 指定的值列表(初始化程序列表)方便地进行初始化:
tbb::concurrent_vector<int> v ({1,2,3,4,5} );
当前,支持初始化程序列表的容器有以下几种:
concurrent_vector
concurrent_hash_map
concurrent_unordered_set
concurrent_unordered_multiset
concurrent_unordered_map
concurrent_unordered_multimap
concurrent_priority_queue
可扩展内存分配程序为每个线程内的已分配内存都提供了高速缓存。 这种做法虽然确保了性能,但通常会增加内存的使用率。 尽管该内存分配程序尽量避免过度使用内存,在复杂的情况下 Intel TBB 4.2 还是会把更多的控制权交给程序设计员: 现在可以通过使用 scalable_allocation_command()函数清理线程高速缓存,进而达到减少内存消耗的目的。 这也有助于大幅提高分配程序的整体性能。
Intel TBB 库已在多种不同平台上获得了广泛的使用。 移动开发人员现在可以在 Linux* 操作系统包中找到适合 Android 的预构建二进制文件。 Windows Store* 应用的二进制文件已经被添加到 Windows* 操作系统包中。
原子变量 tbb::atomic<T>现在在 C++11 中使用时已经具备了构造函数。 这允许程序设计员在声明时就对它们的值进行初始化,同时正确支持构造表达式。 此时,以下代码对 gcc 和 Clang 编译器是有效的:
tbb::atomic<int> v=5;
新社区预览特性允许等待,直到所有工作线程终止。 在应用程序分解进程时,这种情况可能很有必要,否则 TBB 动态库可能会从运行时中卸载掉(例如,假如 TBB 是一个插件的一部分)。 如果您想启用工作线程等待功能,请按以下方式对 task_scheduler_init对象进行初始化:
#define TBB_PREVIEW_WAITING_FOR_WORKERS 1 tbb::task_scheduler_init scheduler_obj (threads, 0, /*wait_workers=*/true);