我编写了一个小C程序,以评估OpenMP在任务中闲置时间时屈服于另一个任务的能力(例如,等待传达的数据):
#include <stdio.h>
#include <sys/time.h>
#include <omp.h>
#define NTASKS 10
double wallClockTime(void) {
struct timeval t;
gettimeofday(&t, NULL);
return (double)(t.tv_sec + t.tv_usec/1000000.);
}
void printStatus(char *status, int taskNum, int threadNum) {
#pragma omp critical(printStatus)
{
int i;
for (i = 0; i < taskNum; i++) printf(" ");
printf(" %s%i n", status, threadNum);
}
}
void task(int taskNum) {
// "r"un task
printStatus("r", taskNum, omp_get_thread_num());
sleep(1);
// "s"leeping task that can yield
printStatus("s", taskNum, omp_get_thread_num());
double idleStartTime = wallClockTime();
while (wallClockTime() < idleStartTime + 1) {
#pragma omp taskyield
}
// "c"ontinue task
printStatus("c", taskNum, omp_get_thread_num());
sleep(1);
}
int main(int argc, char* argv[]) {
#pragma omp parallel
#pragma omp single nowait
{
int i;
printf("thread %d is masternn", omp_get_thread_num());
for (i = 0; i < NTASKS; i++) printf(" %02d ", i);
printf("n");
for (i = 0; i < NTASKS; i++) {
#pragma omp task untied
task(i);
}
}
return 0;
}
我使用了Intel C编译器17.0.4。这是带有3个线程的运行的输出:
thread 0 is master
00 01 02 03 04 05 06 07 08 09
r1
r0
r2
s1
s0
s2
r0
c1
c2
s0
r0
r1
r2
s0
r0
s1
s2
s0
r0
c1
c2
s0
r0
s0
c0
c0
c0
c0
c0
c0
线程1和2根本不屈服,但它们坚持其分配的任务。我还希望线程1和2继续在悬挂的未键任务04 ... 09上继续,但是这些仅由主线程0处理,而其他线程是空闲的。
是否必须以不同的方式发布或屈服这些任务,还是Intel的OpenMP运行时(尚未)可以处理此任务?顺便说一句,GNU GCC 4.9.2根本不屈服。
我认为您的代码很好,这是一个实现问题。实际上,在LLVM OpenMP实施中,这与英特尔的实施非常相关 - 两周前推动了一项提交,从而解决了您的问题。在我的测试中,Clang的当前libiomp5.so
(由中继构建)仅通过设置LD_LIBRARY_PATH
并产生所需的结果与icc 17.0.4
兼容。
thread 0 is master
00 01 02 03 04 05 06 07 08 09
r0
r2
r1
s0
r0
s2
r2
s1
r1
s0
r0
s2
r2
s1
r1
s0
r0
s2
s1
c2
s0
c1
c0
c2
c1
c0
c2
c1
c0
c0
我也可以确认GCC根本没有屈服,但没有详细研究。
我不知道是否以及何时将更改合并到Intel运输的库中。
更新:您是正确的,行为仍然不是最佳的。从简要浏览代码,libiomp
似乎支持绑定的任务的概念,而是在taskwait
期间不需要该任务,而只是执行另一个任务并保留堆栈中暂停任务的上下文。我怀疑适当的支持将需要更多的重型编译器支持(一种连续),而不仅仅是生成库电话。
再次,您正在做正确的事情,但是编译器/运行时还不够复杂,无法支持标准允许(该行为完全符合标准标准)。另请注意,对于libiomp
的当前行为,甚至不需要任何任务,因为它们只是到目前为止的排队。似乎没有一种简单的方法来获得所需的东西,而没有分解/链式任务。