- 浏览: 2037153 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (651)
- ACE (35)
- BAT (9)
- C/C++ (116)
- fast-cgi (14)
- COM (27)
- python (59)
- CGI (4)
- C# (2)
- VC (84)
- DataBase (29)
- Linux (96)
- P2P (6)
- PHP (15)
- Web (6)
- Memcached (7)
- IME输入法 (11)
- 设计模式 (2)
- 搜索引擎 (1)
- 个人情感 (4)
- 笔试/面试 (3)
- 一亩三分地 (33)
- 历史 (2)
- 地理 (1)
- 人物 (3)
- 经济 (0)
- 不仅仅是笑哦 (43)
- 小故事大道理 (2)
- http://www.bjdsmyysjk120.com/ (0)
- http://www.bjdsmyy120.com/ (0)
- 它山之石可以攻玉 (15)
- 大学生你关注些什么 (28)
- 数据恢复 (1)
最新评论
-
luokaichuang:
这个规范里还是没有让我明白当浏览器上传文件时,STDIN的消息 ...
FastCGI规范 -
effort_fan:
好文章!学习了,谢谢分享!
com技术简介 -
vcell:
有错误os.walk(strPath)返回的已经是全部的文件和 ...
通过python获取目录的大小 -
feifeigd:
feifeigd 写道注意:文章中的CPP示例第二行 #inc ...
ATL入门:利用ATL编写简单的COM组件 -
feifeigd:
注意:文章中的CPP示例第二行 #include " ...
ATL入门:利用ATL编写简单的COM组件
在多线程程序中,普通的内存分配将成为严重的性能瓶颈。本文介绍了怎样使用Threading Building Blocks的可扩展内存分配器来避免内存分配竞争和假共享问题。
内存分配不仅是编程的基本任务,也是在多核编程时影响效率的一大挑战。在C++里我们可以用自定义内存分配器代替std:: allocator,Threading Building Blocks就提供了一个与std::allocator兼容的可扩展内存分配器。
每个内存分配器都有自己的特点。TBB的可扩展分配器致力于可扩展性和速度。在某些情况下,这是有代价的:浪费虚拟空间。具体来说,当 分配9k到12k的块可它会浪费较大的空间。
内存分配问题
在多线程程序中,普通的内存分配将成为严重的性能瓶颈。这是因为普通的内存分配器用一个全局锁从一个单一的全局堆中分配和释放内存块, 每个线程分配和释放内存时就会引发竞争。正是由于这种竞争,频繁内存分配的程序可能降低多核带来的优势。使用C++标准库(STL)的程序可能会更为严 重,因为它们的内存分配往往隐藏在背后。
这里先放一段代码,它并发地执行一个有内存申请和释放操作的函数:
#include <iostream> #include <tbb/parallel_for.h> #include <tbb/tick_count.h> #include <vector> using namespace tbb; void alloctask( int ) { //vector构造和析构时会申请和释放空间 std::vector<int> data(100); } int main() { tick_count t1 = tick_count::now(); //用于记录花费的时间 parallel_for(0,100000,1,alloctask); //十万次执行alloctask(并发) tick_count t2 = tick_count::now(); std::cout << (t2-t1).seconds() << std::endl; return 0; }
你可以运行这段代码查看所花费的时间,我们可以很容易地把上面的代码修改成使用TBB可扩展内存分配器,这样速度会加快将近一倍(在偶 双核CPU上,预计更多内核的CPU会有更好的表现)。
注:如果之前看过本站关于TBB循环的 文章的朋友可能会奇怪,这里没有task_scheduler_init,而且parallel_for的参数也不一样。其实这段代码是基于最新的TBB2.2版 本的,这个版本已经不再强制要求task_scheduler_init。parallel_for也多了几个重载以方便使用。
“假共享”是并发程序中另一个严重问题,它常发生于当多个线程使用的内存块紧靠在一起时。在处理器内核中有一个称为“cache lines”的高速缓存区,它只能由同一个线程存取同一个缓存区,否则就会引发缓存切换,这可以轻易地造成上百时钟周期的浪费。
为了说明为什么假共享有这样的性能损失,我们可以看看当两个线程访问紧靠在一起的内存时引起的额外的开销。假设这个缓存区有64字节, 两个线程共享这个缓存。
首先,程序定义了两个数组,包含1000个float(4字节):
float A_array [1000]; float B_array [1000];
由于编译器的顺序分配,这两个数组很可能是紧靠在一起的。考虑下面的动作:
- 线程A写入A_array[999];
处理器将包含A_array[999]这个元素的64个字节放入缓存 - 线程B写入B_array [0];
额外的开销:处理器必须刷新缓存,把A_array[999]保存到内存中。把包含B_array[0]的64个字节载入缓存并设置线程A的缓存 标记为无效。 - 继续工作,线程A写入A_array[1];
额外的开销:处理器必须刷新缓存,以便把B_array [0]保存到内存中。重新为线程A加载缓存并设置线程B的缓存标记为无效。
看,即使线程A和线程B使用各自的内存还是会造成极大的开销。解决方法假共享的办法是把数组按缓存边界对齐。
内存分配器
TBB的可扩展内存分配器可以用来解决上面所述的问题,TBB提供了两个分配器:scalable_allocator和cache_aligned_allocator,它们分别定义于tbb/scalable_allocator.h和 tbb/cache_aligned_allocator.h里。
- scalable_allocator 解决了分配竞争的情况,它并没有完全防止假共享。不过每个线程从不同的内存池中取得内存,这也可以从一定程 序上避免假共享的发生。
- cache_aligned_allocator 解决了分配竞争和假共享问题。由于分配的内存是缓存大小的倍数所以要花费更多的空间,尤其是分配大量小空 间时。我们应该在确定假共享已成为性能瓶颈时才使用cache_aligned_allocator。在你的程序中分别使用两种分配器来测试性能以确定最 终使用哪一个是个好主意。
在STL容器中使用分配器
scalable_allocator和cache_aligned_allocator与std::allocator是兼容的,我们可以和使用 std::allocator一样使用它们。下面的例子演示了使用cache_aligned_allocator作为std::vector的分配器。
std::vector< int, cache_aligned_allocator<int> >;
现在我们可以把前面的代码修改一下了:
void alloctask( int ) { //vector构造和析构时会申请和释放空间 std::vector<int, scalable_allocator<int> > data(100); }
对比一下在你的电脑上效率提升了多少吧^_^
TBB为malloc,free,realloc和calloc提供了对应的可扩展版本: 要完整地重载C++中的new和delete,我们要实现下面这四对new/delete操作: 我们可以利用前面说到的scalable_malloc()和scalable_free()来实现这些操作:代替malloc,free,realloc和calloc
#include "tbb\scalable_allocator.h"
void * scalable_malloc (size_t size);
void scalable_free (void* ptr);
void * scalable_realloc (void* ptr, size_t size);
void * scalable_calloc (size_t nobj, size_t size);
代替new和delete
void* operator new(std::size_t size) throw(std::bad_alloc);
void* operator new(std::size_t size, const std::nothrow_t&) throw( );
void* operator new[](std::size_t size) throw(std::bad_alloc);
void* operator new[](std::size_t size, const std::nothrow_t&) throw( );
void operator delete(void* ptr) throw( );
void operator delete(void* ptr, const std::nothrow_t&) throw( );
void operator delete[](void* ptr) throw( );
void operator delete[](void* ptr, const std::nothrow_t&) throw( );
#include "tbb\scalable_allocator.h"
void* operator new (size_t size) throw (std::bad_alloc)
{
if (size == 0) size = 1;
if (void* ptr = scalable_malloc (size))
return ptr;
throw std::bad_alloc ( );
}
void* operator new[] (size_t size) throw (std::bad_alloc)
{
return operator new (size);
}
void* operator new (size_t size, const std::nothrow_t&) throw ( )
{
if (size == 0) size = 1;
if (void* ptr = scalable_malloc (size))
return ptr;
return NULL;
}
void* operator new[] (size_t size, const std::nothrow_t&) throw ( )
{
return operator new (size, std::nothrow);
}
void operator delete (void* ptr) throw ( )
{
if (ptr != 0) scalable_free (ptr);
}
void operator delete[] (void* ptr) throw ( )
{
operator delete (ptr);
}
void operator delete (void* ptr, const std::nothrow_t&) throw ( )
{
if (ptr != 0) scalable_free (ptr);
}
void operator delete[] (void* ptr, const std::nothrow_t&) throw ( )
{
operator delete (ptr, std::nothrow);
}
<<完>>
发表评论
-
Berkeley DB 使用经验总结
2012-08-27 14:41 3087作者:陈磊 NoSQL是现在互联网Web2.0时代备受 ... -
嵌入式数据库系统Berkeley DB
2012-08-27 14:37 1534前言 UNIX/LINUX平台下的数据库种类非常多 ... -
C语言中标准输入流、标准输出流、标准错误输出流
2011-06-13 14:32 9294C语言中标准输入流、标准输出流、标准错误输出流 在 ... -
Rsync 实现原理
2011-05-12 20:06 8323Rsync 实现原理 前言 关于rsync的原始文档 ... -
c++简单的虚函数测试
2011-04-27 14:25 1022#include <iostream> u ... -
C++文件行查找
2011-04-26 14:10 1409#include <iostream> # ... -
c++偏特化简单示例
2011-04-13 11:17 2157c++偏特化 // temp1.c ... -
GDB调试精粹及使用实例
2011-03-16 14:06 1142GDB调试精粹及使用实例 一:列文件清单 1. ... -
简单的ini文件解析
2011-02-12 16:36 1624int GetKeyVal(const string s ... -
scanf族函数高级用法
2011-01-25 16:00 2563如何解释 fscanf(fd,&quo ... -
使用scons替代makefile(1)
2011-01-25 11:58 3735早在多年前我刚开始接触linux下的C程序时,经常被makef ... -
使用scons替代makefile(2)
2011-01-25 11:57 3585本篇文章接着上一篇进一步介绍scons的使用方法,主要介绍静态 ... -
使用scons替代makefile(3)
2011-01-25 11:55 4822在上两篇文章中已经简单介绍了用scons编译库文件,可执行程序 ... -
C 支持动态添加测试数据的测试代码
2011-01-13 17:22 1121/下面的定义为了支持可扩增。 //当需要增加一个新的测试用列 ... -
Linux下Makefile的automake生成
2010-12-28 16:55 1103******************helloworld.c* ... -
SCons笔记(详细版)
2010-12-23 16:11 105441. 基本使用 SConstruct文件就功能而言相当于Ma ... -
scons 学习
2010-12-23 11:14 2184scons 学习 作者:Sam(甄峰) sam_code@h ... -
scons随笔
2010-12-22 20:20 4709scons随笔 Scons是新一代的软件构件工具,或者说ma ... -
Scons在linux下的安装和使用
2010-12-21 11:59 3289因为正在用的一个开源软件需要的Developm ... -
排列组合的实现
2010-12-20 12:41 1066简单算法: 从前往后(或者从后往前)每次交换一个位置。当存在 ...
相关推荐
TBB中的并发容器是其核心特性之一,它们是为了在多线程环境中安全有效地共享数据而设计的。这些容器包括: 1. `concurrent_queue`:这是一个线程安全的队列,允许在多个线程之间并发地进行入队和出队操作。它使用锁...
TBB 开源库的主要组成部分包括算法模块、流程图模块、任务调度模块、容器模块、线程局部存储模块、内存分配模块、互斥模块、时间模块、同步原语模块等。这些模块的作用如下所示: * 算法模块:提供一些通用的并行...
**TBB库——线程构建模块** TBB(Thread Building Blocks)是由Intel开发的一个开源库,全称为...总的来说,TBB是一个强大的工具,它简化了多线程编程的复杂性,让开发者能够更专注于解决问题,而不是处理并发问题。
5. **智能内存管理**:TBB提供了内存池和可重用对象池,可以更有效地管理内存,减少内存分配和释放的开销,从而提升性能。 6. **同步原语**:TBB提供了一些轻量级的同步原语,如mutex、semaphore和condition_...
5. **内存分配器**:TBB还提供了一种高效的内存分配策略,减少了内存碎片,提高了内存分配和释放的性能。 6. **并发实用工具**:如屏障同步、读写锁、条件变量等,都是TBB提供的基础并发原语,便于开发者构建复杂的...
TBB的主要目标是解决在多核时代遇到的并发编程挑战,如任务调度、数据并行处理、内存管理以及同步问题。通过TBB,开发者可以创建可伸缩的、高性能的程序,而无需深入研究底层线程管理和同步机制的复杂性。 TBB的...
4. **智能内存管理**:TBB提供了一种名为“arena”的内存管理机制,确保在多线程环境下的内存分配是线程安全的,同时优化了内存的使用。 5. **同步原语**:TBB提供了一些高级的同步原语,如mutexes、semaphores和...
6. **可扩展的内存分配器(Scalable Memory Allocator)**:TBB内建了一个内存分配器,能够在多线程环境中提供更好的性能和内存利用率。 在Linux环境下安装和使用TBB2019.0.117版本,通常包括以下步骤: 1. **下载...
**正文** Intel TBB(Thread Building Blocks)是Intel公司推出的一款高效的并行编程库,专为多核处理器设计,旨在简化并行编程的...使用TBB,开发者可以更专注于解决业务问题,而不是关注底层的线程管理和同步细节。
在开发过程中,调试版本的库通常包含额外的检查和诊断信息,帮助程序员在调试代码时发现并解决问题。OpenCV,即Open Source Computer Vision Library,是一个广泛使用的计算机视觉和机器学习软件库,它可能依赖于TBB...
5. **内存管理**:TBB提供了可扩展的内存分配器,可以减少锁竞争,提高多线程环境下的内存分配效率。 6. **兼容性**:TBB3.0支持Windows、Linux和Mac OS等多个操作系统,以及intel64和ia32两种处理器架构。 【与...
6. **内存管理**:TBB还提供了线程安全的内存分配器,如`tbb::scalable_allocator`,它能够有效地管理多线程环境下的内存分配,避免因竞争条件导致的性能下降。 7. **队列和管道**:`tbb::concurrent_queue`和`tbb:...
TBB库能够根据系统资源(如CPU核心数量、内存大小)自动调整并行度,确保在不同硬件配置下都能获得良好的性能。 **7. 示例代码分析** 在`tbb43_20150424oss`这个压缩包中,我们可以找到TBB库的源代码和示例程序。...
3. **数据结构**:TBB 包含了一些并发友好的数据结构,如队列、堆和映射,它们可以在多线程环境中安全地使用。 4. **流处理接口**:TBB 提供了一个流处理模型,允许开发者构建数据流网络,其中数据在操作之间流动,...
TBB提供了一套丰富的模板类和函数,帮助开发者编写高效的多线程程序,使得程序员可以专注于解决算法问题,而无需深究底层线程管理的复杂性。在给定的“inteltbb.rar”压缩包中,包含了一系列资源,用于在Windows 7...
CMakeLists.txt文件用于定义项目配置,包括找到依赖项如TBB,设置编译选项,以及生成实际的构建文件(如Makefile或Visual Studio解决方案)。 在编译OpenCV时,TBB作为依赖项,需要被正确配置和链接。以下是一些...
8. **内存管理**:TBB还提供了智能内存分配器,可以减少锁的争用,提高多线程环境下的内存管理效率。 通过这个压缩包,用户可以获得OpenCV与TBB的集成,从而在进行计算机视觉项目时,享受到更高效的并行计算能力,...
3. **容器和同步原语**:为了简化并发编程中的数据管理问题,TBB 还提供了线程安全的容器(如_concurrent_vector_)以及锁、信号量等同步机制。 4. **自适应算法**:TBB 支持自适应算法,可以根据运行时环境动态调整...
5. **内存分配器**:优化的内存分配策略,减少了锁竞争,提高并行性能。 6. **接口兼容性**:TBB与标准C++库兼容,易于集成到现有的C++项目中。 7. **跨平台性**:TBB不仅支持Windows,还支持Linux、macOS等其他操作...