我只想生成一个后台线程,例如 std::thread,但仅使用 OpenMP。 这可能吗? 如果是的话,是怎么做到的? 为了更好地解释我想要实现的目标,这里是我想要做的 C++ 代码:
//05.06.2024
//How to spawn a single thread with OpenMP (like a std::thread()) and use "#pragma omp single" and
//"#pragma omp for" afterwards? This here does not work! (as expected)
//OS: Linux Mint 21.3, Kernel: 6.5.0-35-generic x86_64 bits
//compiler: g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
// g++ -O2 openmp_single_bkgtask_test.cpp -fopenmp
#include <omp.h>
#include <iostream>
#include <unistd.h>
void backgroundWork()
{
while(true)
{
std::cout<<"background work!"<<std::endl;
usleep(1e6);
}
}
int main()
{
omp_set_num_threads(8);
#pragma omp parallel
{
#pragma omp single nowait
#pragma omp task
backgroundWork();
while(true)
{
#pragma omp single
std::cout<<"loading data"<<std::endl;
//++++++++++
//prog never comes beyond this point, because "#pragma omp single" is waiting after
//"loading data" for the <task>-thread to finish (which of course does not happen
//++++++++++
#pragma omp for
for(int i=0;i<16;i++)
{
std::cout<<"processing data "<<i<<std::endl;
}
}
}
return 0;
}
我知道这行不通,因为 omp 单指令将等待所有线程,但“任务”中“缺少”一个线程,因此它按预期“工作”。 但如何在 OpenMP 中生成线程?
这是仅使用任务的解决方案,以及整个并行区域的
omp single
编译指示:
int main()
{
#pragma omp parallel
#pragma omp single
{
#pragma omp task
backgroundWork();
int v = 0;
while(true)
{
v++;
#pragma omp critical
std::cout<<v<<" loading data"<<std::endl;
#pragma omp taskloop
for(int i=0;i<4;i++)
{
usleep(1e5);
#pragma omp critical
std::cout<<v<<" processing data "<<i<<std::endl;
}
}
}
return 0;
}
根据 Jerôme Richard 的建议,将
omp for
替换为 omp taskloop
。 critical
编译指示只是为了更好地格式化文本输出。
由于执行
single
区域的线程在任务循环执行期间不执行任何操作,因此与核心数量相比,您可以多使用一个线程。另一种情况是后台任务几乎不执行任何操作。
请注意,实际上并不能保证后台任务首先执行(允许 OpenMP 运行时自行调度任务),尽管实际上很有可能是这样。保证执行的另一种选择是基于部分:
int main()
{
#pragma omp parallel sections
{
#pragma omp section
backgroundWork();
#pragma omp section
{
int v = 0;
while(true)
{
v++;
#pragma omp critical
std::cout<<v<<" loading data"<<std::endl;
#pragma omp taskloop
for(int i=0;i<4;i++)
{
usleep(1e5);
#pragma omp critical
std::cout<<v<<" processing data "<<i<<std::endl;
}
}
}
}
return 0;
}
带有部分和嵌套并行性的第三种解决方案:
int main()
{
omp_set_nested(1);
#pragma omp parallel sections num_threads(2)
{
#pragma omp section
backgroundWork();
#pragma omp section
{
int v = 0;
while(true)
{
v++;
#pragma omp critical
std::cout<<v<<" loading data "<<omp_get_thread_num()<<std::endl;
#pragma omp parallel for num_threads(2)
for(int i=0;i<4;i++)
{
usleep(1e5);
#pragma omp critical
std::cout<<v<<" processing data "<<i<<" "<<omp_get_thread_num()<<std::endl;
}
}
}
}
return 0;
}