【问题标题】:Multiple Threads of C++ application block each other while (de-)allocating memoryC++ 应用程序的多个线程在(取消)分配内存时相互阻塞
【发布时间】:2022-06-29 16:48:09
【问题描述】:

世界,

我尝试使用多线程运行 C++ 应用程序(在 VS 中编译为 .exe),并为此使用 QThread 或 omp-parallelization。在使用 umfpack 求解从这些矩阵构建的方程系统之前,每个线程都会执行多次内存分配/解除分配以执行大型矩阵计算。现在,当我使用太多线程时,我会降低性能,因为线程在执行此操作时会相互阻塞。我已经读过内存(取消)分配一次只能用于一个线程(如互斥条件)。

我已经尝试过的:

  • 尽我所能减少大量重新分配
  • 使用不同的并行化方法(Qt 与 omp)
  • 随机更改保留和提交的堆栈/堆大小
  • 将 umfpack 数组设为线程私有

在我的设置中,在性能下降之前,我可以使用 ~4 个线程(每个线程使用 ~1.5 GB RAM)。有趣的是——但我还无法理解——只有在几个线程完成并且新线程接管之后,性能才会降低。另请注意,线程之间不相互依赖,没有其他阻塞条件,每个线程运行的时间大致相同(约 2 分钟)。

有没有“简单的方法” - 例如以某种方式设置堆/堆栈 - 来解决这个问题?

这里有一些代码sn-ps:

// Loop to start threads

forever
{
    if (sem.tryAcquire(1)) {
        QThread *t = new QThread();
        connect(t, SIGNAL(started()), aktBer, SLOT(doWork()));
        connect(aktBer, SIGNAL(workFinished()), t, SLOT(quit()));
        connect(t, SIGNAL(finished()), t, SLOT(deleteLater()));
        aktBer->moveToThread(t);
        t->start();
        sleep(1);
    }
    else {
        //... wait for threads to end before starting new ones
        //... eventually break
    }
    qApp->processEvents();
}

void doWork() {
    // Do initial matrix stuff...
    
    // Initializing array pointers for umfpack-lib
        static int *Ap=0;
        static int *Ai=0;
        static int *Ax=0;
        static int *x=0;
        static int *b=0;

    // Private static Variablen per thread
    #pragma omp threadprivate(Ap, Ai, Acol, Arow)

    // Solving -> this is the part where the threads block each other, note, that 
              there are other functions with matrix operations, which also (de-)/allocate a 
              lot
    status = umfpack_di_solve (UMFPACK_A, Ap,Ai,Ax,x,b, /*...*/);
    
    emit(workFinished());
}

【问题讨论】:

  • 您可以尝试预分配到池中,或者切换到不序列化所有分配和释放的不同分配器。见stackoverflow.com/q/147298/103167
  • 谢谢。使用新的分配器来实例化线程对象是否就足够了,还是我必须在我的代码中交换所有“新”语句?
  • 一个好的分配器可以选择替换系统分配器(在 C++ 中它被命名为::operator new()),所以你不必重写代码。根据您在矩阵运算中发生争用的说法,仅更改 Thread 对象的分配是不够的。
  • 提醒——还有第三种选择——静态。您可以在静态数据中保留一个喇叭大数组

标签: c++ multithreading memory-management


【解决方案1】:

对于那些对我的解决方案感兴趣的人:我在我的应用程序中包含了另一个分配器(正如@Ben Voigt 建议的那样)。就我而言,我选择了 mimalloc,因为它似乎得到了定期维护(甚至由 microsoft 本身)并且可以很容易地包含在内。 See here: Mimalloc

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-18
    • 2012-10-22
    • 1970-01-01
    相关资源
    最近更新 更多