在QThread上使用时,OpenMP线程仅在一个CPU上运行.(Qt,C++)
OpenMP threads only run on one CPU when used on a QThread. (Qt, C++)
我正在尝试编写粒子模拟。我创建了一个工作类,所有的计算都在其中进行,并使用movetothread()
将其移动到QThread
,以保持GUI的响应性(有效(。
现在为了加快计算速度,我想在worker中使用openMP。奇怪的是,所有的openMP线程似乎都只在一个CPU内核上运行。我注意到了这一点,因为无论是否使用openMP,CPU使用率(在4个逻辑核上约为25%(和运行模拟的时间都不会改变。
当在工作者中调用omp_get_num_procs()
时,它返回4,但我没有观察到加速。我手动将num_threads()
设置为4只是为了确定,但没有帮助。
程序会编译并且计算正确(使用openMP时也是如此(。
我听说同时使用QThread
s和openMP时可能会出现问题。显然,openMP派生的所有线程都只在分配给工作线程的CPU上运行。
我使用的是Windows 10 64位,Qt Creator 3.6.1,Qt 5.6.0(MSVC 2013,32位(。在.pro
文件中,我添加了QMAKE_CXXFLAGS += -fopenmp
和QMAKE_LFLAGS += -fopenmp
。也称为LIBS += -fopenmp
。
qmake是:
qmake.exe ParticleSimulations.pro-r-spec win32-g++"CONFIG+=debug"CONFIG++=qml_debug">
品牌:
C:\中的mingw32-make.exe。。。
编辑:我还调用了"omp_get_num_threads((",返回4。我感兴趣的是线程是在单独的CPU上运行还是只在一个CPU上运行。
编辑:根据请求,这里是我的一些代码(不确定它是否有多大帮助(这来自mainwindow.cpp,在这里创建了负责计算的第二个QThread:
Pot=new LennardJones(sig,eps,mass,acc);
if (ParticlesTypeID==0)
Part=new TestParticles(confDia->getTestParticlesID(),L,Duration);
else if (ParticlesTypeID==1)
Part=new RandomParticles(n,L,Duration);
else if (ParticlesTypeID==2)
Part=new FileParticles(confDia->getValuesFromFile(),L,Duration);
thread = new QThread;
Pot->moveToThread(thread);
connect(Pot, SIGNAL(finished()), thread, SLOT(quit()));
connect(Pot, SIGNAL(finished()), Pot, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(this, SIGNAL(CancelClick()), Pot, SLOT(onCancelClick()));
connect(Pot, SIGNAL(sendProgress(int)), this, SLOT(on_Progress(int)));
connect(Pot, SIGNAL(sendTime(double)), this, SLOT(on_Time(double)));
thread->start();
// Calculation
Part->setParticleData(Pot->Newton(Part->getParticleData(),Part->gettspan(),Part->getL(),MaxNewtonIterations,MaxSteps,MinSteps));
这是计算的一部分(只是一个例子(。在那里调用omp_get_num_threads((或omp_get_num_procs((让我相信OpenMP原则上是有效的。
void LennardJones::NewtonIteration(Eigen::MatrixXd &ParticleData, Eigen::VectorXd &FirstDer, Eigen::MatrixXd &SecDer, Eigen::VectorXd &GKplus1, Eigen::MatrixXd &GderInvKplus1, Eigen::MatrixXd &temp, int &k, double &deltat, int &maxiterations){
int counter=0;
while(((temp-ParticleData.col(k)).norm() > accuracy) && (counter<maxiterations)){
#pragma omp parallel sections
{
#pragma omp section
{
FirstDer=FirstDerivative(ParticleData);
GKplus1=BuildGKplus1(ParticleData,FirstDer,deltat);
}
#pragma omp section
{
SecDer=SecondDerivative(ParticleData);
GderInvKplus1=BuildGderInvKplus1(ParticleData,SecDer,deltat);
}
}
temp = ParticleData.col(k);
ParticleData.col(k)=ParticleData.col(k)-GderInvKplus1*GKplus1;
counter++;
}
}
另一个代码片段。在这里,我尝试将运行n次的for循环并行化(n是粒子数,因此应该有很大的性能提升空间(
#pragma omp parallel for
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
if(j!=i){
//Positionsvektoren die in diesem Schritt betrachtet werden
v1K=ParticleData.block(3*(n+i-1),ParticleData.cols()-2,3,1);
v2K=ParticleData.block(3*(n+j-1),ParticleData.cols()-2,3,1);
v1Kplus1=ParticleData.block(3*(n+i-1),ParticleData.cols()-1,3,1);
v2Kplus1=ParticleData.block(3*(n+j-1),ParticleData.cols()-1,3,1);
//Distanz r
rK = (v1K-v2K).norm(); //Distance(v1K,v2K);
rKplus1 = (v1Kplus1-v2Kplus1).norm(); //Distance(v1Kplus1,v2Kplus1);
//Großer ausklammerbarer Term in der ersten Ableitung
tempK=-12*epsilon*(pow(sigma,12)/pow(rK,14) - pow(sigma,6)/pow(rK,8));
tempKplus1=-12*epsilon*(pow(sigma,12)/pow(rKplus1,14) - pow(sigma,6)/pow(rKplus1,8));
// Erste Ableitungen
FirstDerK.segment(3*i-3,3)+=tempK*(v1K-v2K);
FirstDerKplus1.segment(3*i-3,3)+=tempKplus1*(v1Kplus1-v2Kplus1);
}
}
}
提前感谢!:(
我将OpenMP与QThread
一起使用,它们可以正确地协同工作。与问题中描述的情况的两个主要区别是:
1( 我正在使用带有GCC6 的Linux
2( 工人类和QThread
类是分开的。我的意思是,有一个纯粹的STL/Eigen/任何东西,但没有Qt,工人类。然后,有一个包装器类,它继承自QObject
,并拥有工作类的一个实例。信号槽连接是在应用程序和包装类之间建立的,包装类反过来调用工作类的方法。
有了这样的设置,并发度等于核心数。
为了进一步调试并发问题,我建议下载免费的Intel Parallel Studio XE并运行配置文件。然后,您将能够观察(a(并发程度和(b(是否正在使用OpenMP,因为当它被使用时,您可以在概要文件中看到_omp
函数。
通过这种方式,我看到在调用启用OpenMP的函数时创建了2个线程(主GUI+QThread
一个(,然后又创建了12个线程(Xeon X5650 HT on(。因此,我得出结论,QThread
线程与OpenMP线程是分开的。顺便说一句,我设法用一个GDB调试器来观察它,因为每次创建新线程时,它都会输出一条消息。
除此之外,我看到建议使用OpenMP的另一组标志:-fopenmp
和-lgomp
。所以,在你的情况下,
QMAKE_CXXFLAGS += -fopenmp
QMAKE_LFLAGS += -lgomp
尽管在GCC5和GCC6上,仅仅第一个标志-fopenmp
就足够了。
- 编写一个函数以使用 n 百分比的 CPU 使用率
- 超过CPU时间限制:当MPI_Sent一个非常大的int*时
- 是否有一个C++函数可以准确返回平方根反比的内置 CPU 操作 RSQRTSS 的值?
- 维护/维持两个代码集的风险,一个用于 CPU,一个用于 GPU,需要执行非常相似的功能
- 如何用一个简单的C++程序测试CPU
- 为什么一个空的无限循环会占用我的整个CPU
- 一个简单的pthread_create导致Qt中的CPU使用率达到100%
- 在每个主机线程(多线程 CPU)上创建一个 cuda 流
- 可视化设置一个c++应用程序使用最大CPU使用率,在代码中
- 硬件是否将多个代码操作合并为一个物理CPU操作
- 实现了一个多cpu的FCFS算法
- 创建一个占用特定CPU和RAM数量的任务
- 编写一个CUDA内核来替换一个等效的cpu函数
- 在有限的cpu时间内定期执行一个pthread
- 如何在一个CPU上运行c++程序
- 当CPU处于挂起或待机状态时,一个定时条件变量(例如std::wait_for)会发生什么?
- 如何在c++中计算一个应用程序所消耗的总内存和CPU使用量
- 你如何减少cpu/帧,而有一个鼠标挂钩,而不引起鼠标拖拽?c++
- 在QThread上使用时,OpenMP线程仅在一个CPU上运行.(Qt,C++)
- 在Win32上,如何将线程移动到另一个CPU核心