1

我刚刚了解到,在 C 语言中,malloc函数在多线程应用程序中使用时会出现线程争用问题。

在 C++ 中是否operator new会遇到同样的问题?如果是,我可以使用什么技术来避免这种情况,这听起来像是对应用程序性能的巨大损失?

4

4 回答 4

2

线程争用的“问题”实际上取决于实现。一些常用的 malloc 实现最初设计时并未考虑多线程。但是为多线程应用程序设计的 malloc 实现在正常情况下不应该受到争用的影响。

作为考虑多线程设计的 malloc 实现的示例,请查看jemalloc

于 2010-10-10T21:13:42.907 回答
0

malloc 中线程争用的问题很简单,就是堆在更新时必须受到类似设备的互斥体的保护。如果两个线程同时更新堆,您将遇到竞争条件。同样的问题也适用于新的,所以没有根本原因为什么一个应该比下一个少。

话虽如此,有许多技巧可以最大限度地减少争用。首先是将堆分解为单独的竞技场。每个竞技场都有自己的锁。如果一个线程试图分配内存并且一个 Arena 被锁定,它只会尝试分配下一个 Arena。

Frees 将需要访问用于 malloc 的相同 Arena。这也可以通过将要释放的指针放在空闲列表中来优化。这可以原子地完成。下一次 Arena 解锁时,free list 上的所有指针都会被正确释放。

这些技术有助于防止但不能消除争用,这意味着在生产者消费者线程模型中,最好让消费者将指针传回生产者,在那里它们可以被重用或酌情删除。

于 2010-10-10T23:59:37.410 回答
0

在 C++ 中,运算符 new 是否会遇到同样的问题?

是的,在大多数实现中,确实如此。

如果您已经使用 C++,Threading Building Blocks是一个可以满足您需求的 C++ 模板库。它具有可扩展的分配器、数据结构、网站等...

于 2010-10-10T22:02:35.150 回答
0

取决于 new 的实现,但它通常是基于 malloc 的。这里有几件事你可以做:

  • 使用分析器来计算每秒调用malloc()(可能是brk())的次数,确保您对malloc().
  • 尝试使用并行内存分配器(即hoard
  • 尽可能使用堆栈:不需要时不要调用 new。还要记住,小副本通常比线程之间共享的指针和数据更易于缓存。
于 2010-10-10T21:14:00.380 回答