Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/151.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 多线程池分配器_C++_Multithreading_Memory Management - Fatal编程技术网

C++ 多线程池分配器

C++ 多线程池分配器,c++,multithreading,memory-management,C++,Multithreading,Memory Management,我在多线程应用程序中使用std::list对象的池内存分配器时遇到一些问题 我所关注的代码部分是隔离地运行每个线程函数(即线程之间没有通信或同步),因此我想为每个线程设置单独的内存池,其中每个池都不是线程安全的(因此速度很快) 我尝试使用共享线程安全的单例内存池,发现性能很差,正如预期的那样 这是我正在尝试做的事情的一个高度简化的版本。伪代码中包含了很多内容,如果让人困惑的话,很抱歉 /* The thread functor - one instance of MAKE_QUADTREE cr

我在多线程应用程序中使用std::list对象的池内存分配器时遇到一些问题

我所关注的代码部分是隔离地运行每个线程函数(即线程之间没有通信或同步),因此我想为每个线程设置单独的内存池,其中每个池都不是线程安全的(因此速度很快)

我尝试使用共享线程安全的单例内存池,发现性能很差,正如预期的那样

这是我正在尝试做的事情的一个高度简化的版本。伪代码中包含了很多内容,如果让人困惑的话,很抱歉

/* The thread functor - one instance of MAKE_QUADTREE created for each thread
 */
class make_quadtree
{
private:

/* A non-thread-safe memory pool for int linked list items, let's say that it's 
 * something along the lines of BOOST::OBJECT_POOL
 */
    pooled_allocator<int> item_pool;

/* The problem! - a local class that would be constructed within each std::list as the
 * allocator but really just delegates to ITEM_POOL
 */
    class local_alloc
    {
    public :
    //!! I understand that I can't access ITEM_POOL from within a nested class like
    //!! this, that's really my question - can I get something along these lines to
    //!! work??
        pointer allocate (size_t n) { return ( item_pool.allocate(n) ); }
};

public :
    make_quadtree (): item_pool()    // only construct 1 instance of ITEM_POOL per
                                     // MAKE_QUADTREE object
    {
    /* The kind of data structures - vectors of linked lists
     * The idea is that all of the linked lists should share a local pooled allocator
     */
        std::vector<std::list<int, local_alloc>> lists;

    /* The actual operations - too complicated to show, but in general:
     *
     * - The vector LISTS is grown as a quadtree is built, it's size is the number of
     *   quadtree "boxes"
     *
     * - Each element of LISTS (each linked list) represents the ID's of items
     *   contained within each quadtree box (say they're xy points), as the quadtree
     *   is grown a lot of ID pop/push-ing between lists occurs, hence the memory pool
     *   is important for performance
*/
    }
};
/*线程函子-为每个线程创建的MAKE_四叉树的一个实例
*/
类生成四叉树
{
私人:
/*一个用于int链表项的非线程安全内存池
*类似于BOOST::OBJECT\u POOL的东西
*/
池分配程序项池;
/*问题是!-一个本地类,它将在每个std::list中构造为
*分配器,但实际上只是委托给项目池
*/
类本地分配
{
公众:
//!!我知道我无法从嵌套类中访问项目池,如
//!!这,那真的是我的问题-我可以按照这些思路来做些什么吗
//!!工作??
指针分配(size_t n){return(item_pool.allocate(n));}
};
公众:
make_quadtree():item_pool()//每个只构造一个item_pool实例
//生成四叉树对象
{
/*数据结构的种类-链表的向量
*其思想是所有链接列表都应该共享一个本地池分配器
*/
向量表;
/*实际操作-太复杂,无法显示,但通常:
*
*-向量列表随着四叉树的构建而增长,它的大小是
*四叉树“盒子”
*
*-列表的每个元素(每个链表)表示项目的ID
*包含在每个四叉树框中(假设它们是xy点),如四叉树
*大量ID在列表之间弹出/推送,因此内存池
*这对性能很重要
*/
}
};

所以我真正的问题是,我希望每个线程函子实例有一个内存池实例,但在每个线程函子中,多个std::list对象之间共享内存池。

为什么不只构造一个本地alloc实例,并引用它来生成四叉树呢?

一个线程特定的分配器是一个很大的挑战

我花了一些时间寻找“现成”的特定于线程的分配器。我找到的最好的是囤积。这提供了一个显著的性能改进,但是囤积有一些严重的缺点

  • 我在测试过程中遇到了一些碰撞
  • 商业许可证是 昂贵的
  • 它将系统调用“挂钩”到 马洛克,一种我认为是狡猾的技术。
所以我决定基于boost::pool和boost::threadspecificptr推出自己的线程特定内存分配器。这需要少量的、非常重要的、非常先进的C++代码,但是现在看起来工作得很好。 我已经有好几个月没有研究过这方面的细节了,但也许我可以再看一次

您的评论是,您正在寻找特定于线程的分配器,但不是线程安全的分配器。这是有意义的,因为如果分配器是线程特定的,则不需要是线程安全的。然而,根据我的经验,只要不发生争用,线程安全的额外负担是微不足道的

然而,所有这些理论都很有趣,但我认为我们应该转向实践。我相信,我们需要一个小型的、安装了仪器的独立程序来演示您需要解决的问题。我在std::multiset分配中遇到了类似的问题,并编写了您可以在这里看到的程序:


如果您可以编写类似的代码来显示您的问题,那么我可以检查我的特定于线程的内存分配器是否可以在您的情况下发挥优势。

我正在考虑这个问题,但我不知道如何为本地分配写一个默认的构造函数(在std::list中会被称为)这将分配引用/指针???@Darren:它不必是默认构造的,您可以在中传递实例。您的意思是我可以在构造列表时传递分配器的实例吗??既然我有一个列表向量,而不是一个容器,那么这样做行吗??当我调整向量大小时,新的列表对象是否得到了正确的分配器??对不起,我通常不这样做,我想我不明白…@达伦:当然可以。它是一个构造函数参数,与任何其他构造函数参数的工作原理相同——当您需要一个新对象时,您可以传入它。好的,我想我明白了,谢谢。我对调用vector.resize()的情况感到困惑。我曾担心它会导致调用默认的ctor(对于std::list),但现在我意识到还有第二个(默认)参数可以用来防止这种情况!我听说过囤积(和其他一些线程分配器),但据我所知(可能是错误的!)它们在某些阶段仍然使用某种线程保护。我真的在尝试设置本地非线程安全池。。。THREADSPECIFICPOINTER是否使用TLS(Windows上的u declspec(thread)),如果是这样的话,我认为我不能使用它,因为我正在编译一个*。dll@Darren:nedmalloc和tcmalloc都使用线程缓存的本地arenas(使用显式TLS,因此其dll是安全的),但任何生产级线程缓存分配器都会偶尔至少输入一次线程锁,在大多数情况下,为本地竞技场请求新的内存页,这也允许在一个线程中分配的内存在另一个线程中传递和释放。我意识到您已经选择了一个答案。但是如果这是Windows,请查看Microquil的SmartHeap或HeapAgent