(GNU+Linux操作系统)多个线程同时调用 malloc()

(GNU+Linux) Multiple threads calling malloc() at the same time

提问人:Kevin Stefanov 提问时间:9/1/2023 最后编辑:Kevin Stefanov 更新时间:9/1/2023 访问量:82

问:

我在网上读到,大多数现代 UNIX 系统默认都带有线程安全的 malloc()。我知道这仅仅意味着一个线程可以安全地调用 malloc(),而另一个线程已经在 malloc() 调用本身的中间。

我正在使用 pthreads 进行多线程处理。我有一个 12 核 CPU,每个内核有 2 个线程。所以总共有 24 个线程。另外,我正在使用 malloc 的 GNU C 库实现。

我的问题是关于在不锁定/等待/阻止的情况下同时执行它们。我在回答中读到,当多个线程同时调用它时,malloc() “使用内部锁定机制”。

所以这是我的问题:

如果 8 个线程碰巧同时调用 malloc(),是否会有 8 个 malloc 调用并行发生,并且它们不会相互干扰?

或者,当一个线程调用 malloc() 时,其他线程必须等待该线程的 malloc 调用完成,然后才能继续自己的 malloc 调用?

(我之所以问这个问题,是因为我刚刚对我的一个 C 程序进行了多线程处理,它确实广泛使用了 malloc() 和 free(),并且加速与使用的线程不是线性的,即使从逻辑上讲它应该是线性的,因为没有一个线程依赖于任何全局的东西,所以不应该发生争用(无论如何在软件中)。我的方案很简单:每个线程调用一个函数,该函数在 1 个线程上大约需要 315 秒才能完成(无多线程),这会对我定义的函数进行数百万次其他调用。由于函数代码是只读的,因此加速并行运行此顶级函数的 X 线程应该没有问题,因为每个线程都使用自己的参数调用它,并且没有线程依赖于任何全局或共享的内容。当我使用 4 个线程时,由于某种原因,时间从 315 秒增加到 710 秒,当我使用 8 个线程时,时间增加到 1400 秒,即使每个线程都在执行与没有多线程的一个线程完全相同的工作,并且需要 315 秒才能完成。那么,这到底是怎么回事??

c 多线程 malloc pthreads gnu

评论

2赞 Erel 9/1/2023
我谦虚地认为你应该问一个关于你的实际问题的问题(所以,为什么即使你跨线程拆分工作,你也不会从加速中受益),并展示你写的代码。附加说明:添加更多线程并不意味着它一定会变得更快(这被称为阿姆达尔定律)。
1赞 Craig Estey 9/1/2023
malloc会做一个内部版本,所以不用担心......仅供参考,将在后台调用这些内部/低级锁定函数。至于您的速度问题,您应该让主线程/主线程在第一个分配之前完成所有分配,并将它们放在每个线程的结构中(最后一个参数指向这一点)。我们真的需要看到你的代码。请编辑您的问题并发布您的代码。使用线程很容易进行更糟糕的问题分解。pthread_mutex_lock/pthread_mutex_unlockpthread_*pthread_createpthread_create
2赞 Craig Estey 9/1/2023
在线程内部进行大量操作是一个瓶颈。有一些分配策略可以缓解这种情况(例如楼板分配)。有关示例,请参阅我的答案:cs50 pset5 拼写器优化malloc/free
3赞 Andreas Wenzel 9/1/2023
如果线程争用过高,glibc 版本将为各个线程使用单独的竞技场。这样,各个线程的分配器通常不会相互阻碍。有关详细信息,请参阅此页面malloc
1赞 Andreas Wenzel 9/1/2023
除非您使用的是 NUMA,否则所有 CPU 内核都将使用相同的内存控制器。因此,如果这是瓶颈,那么添加额外的 CPU 内核不会给您带来显着的速度提升。

答:

5赞 John Bollinger 9/1/2023 #1

如果 8 个线程碰巧同时调用 malloc(),是否会有 8 个 malloc 调用并行发生,并且它们不会相互干扰?

除其他外,这取决于实施。用于通用操作系统的现代 C 标准库通常适用于同时进行多处理。malloc()

例如,Glibc 的 malloc 维护了多个内存领域,以便从中分配,以避免单个调用迫使所有其他调用阻塞,直到它完成。它自适应地管理这些,但默认情况下,允许的竞技场数量是系统中 CPU 数量的八倍。当然,这是每个过程。如果您在基于 Glibc 的系统上运行,那么,您的 8 个调用可能确实同时进行。没有任何干扰是一个非常高的标准,但我认为可以肯定地说,通常干扰很小。malloc()malloc

在其他系统上,答案可能有所不同。特别是,Windows 的分配器总体上性能不佳,尽管我不太清楚它在多线程应用程序中的处理情况。


然而,如果你的线程做了太多的动态内存管理,以至于你认为这可能是性能问题的根源,那么这可能太多了。即使这不是扩展线程数的特定问题,并且速度相对较慢,因此您应该尝试在性能很重要的情况下尽量减少它们的使用。mallocfree