现在的位置: 首页 > 综合 > 正文

关于多线程里内存分配的问题

2013年08月20日 ⁄ 综合 ⁄ 共 1539字 ⁄ 字号 评论关闭

by    mayflowers

 

 

Quote:
资料上说User::Alloc 这个API 不是线程安全的(似乎除了继承RHandleBase的类是线程安全的其他有关内存的分配的API貌似都不是线程安全的)

那么如果我用了多线程技术,并且这些线程共享了堆区(如果不是共享堆区也就没啥问题了),那么在这些线程里(包括主线程,一般是UI线程)用到User::Alloc的地方都得使用 同步操作(RMutex等)以保证线程安全,那么问题来了,如果是一般的C类呢,分配内存的时候(NEW的时候)是不是也需要进行同步操作呢?如果需要,那么我看到很多例子里在副线程的启动函数里一般都会先创建清除栈,那也是C类,但似乎也从来没有使用 同步操作啊?而且即使C类分配内存都需要加同步操作,这个工程也似乎也忒大了点吧(而且主线程里可能在启动了副线程后可能也要进行一些C类的分配内存,那也就是说这些C类难道也得加上同步操作??

如果两个线程共享堆,而且都有可能执行内存分配和释放操作,就必须进行同步保护,这个和C类,R类,T类没有关系。你看到的例子两个线程应该是使用各自的堆。

在 windows 等平台上,不同线程缺省使用同一个堆,所以用 C 的 malloc (或者 windows 的 GlobalAlloc)分配内存的时候是使用了同步保护的。如果没有同步保护,在两个线程同时执行内存操作的时候会产生竞争条件,可能导致堆内内存管理混乱。比如两个线程分配了统一块内存地址,空闲链表指针错误等。

Symbian 的线程一般使用独立的堆空间。这样每个线程可以直接在自己的堆里分配和释放,可以减少同步所引入的开销。当线程退出的时候,系统直接回收线程的堆空间,线程内没有释放的内存空间也不会造成进程内的内存泄漏。

但是两个线程使用共用堆的时候,就必须用 critical section 或者 mutex 进行同步保护。否则程序崩溃时早晚的事。如果你的线程需要在共用堆上无规则的分配和释放任何数量和类型的对象,可以定制一个自己的 allcator,在 allocator 内部使用同步保护。线程直接使用这个 allocator 分配内存就可以了。这相当于实现自己的 malloc,free。但是更建议你重新审查一下自己的系统,因为这种情况大多数是不必要的。经过良好的设计,线程的本地堆应该能够满足大多数对象的需求。如果有某一类对象需要在共享堆上创建和共享,这种需求是比较合理的,可以在这个类的 new 和 delete 上实现共享保护。

Quote:
还有就是动态数组RArray的问题,资料显示它也不是线程安全的,由于在APEND的过程中可能需要内存的重新分配,也就是说如果用到上面的共享堆区多线程技术的话,那么我在使用RArray的时候也必须加上同步操作吗

同步保护分为算法级和容器级。容器级是指,对于数组这个容器而言,他的插入、删除等操作收到内在的同步保护。不会有两个会改变系统状态的操作同时进行。算法级是指对于某种特定的算法来说是安全的。比如一个线程要删除满足某个条件的所有项,这时候,仅仅在数组的实现里面对删除一个元素的操作进行同步保护是不够的。因为在两次删除之间,可能有别的线程改变数组的状态。这时候需要算法级的同步保护。算法级的安全通常在容器外由客户端提供。

Symbian的RArray没有任何一个级别的同步保护。如果你的数组被一个线程在本地堆上使用,不需要同步。如果只被一个线程在共享堆上使用,只需要保证分配和释放内存的操作是安全的就可以了。如果需要被多个线程共同操作,还需要根据需要提供容器级或者算法级的同步保护。


by mayflowers

There is always a solution, which is so appealing, so quick and so wrong.

抱歉!评论已关闭.