OpenACC中routine内调用exit()库函数遇未定义引用错误求助
解决OpenACC中调用exit()出现未定义引用的问题
遇到这个问题很正常——exit()是标准C库的主机端函数,GPU设备端根本没有它的实现,所以nvlink找不到对应的符号是必然的。你之前用#pragma acc routine解决的是自定义函数的设备端生成问题,但标准库的主机函数没法这么处理,得换个思路。
给你两个靠谱的解决方案,按推荐程度排序:
方案一:用OpenACC标准的acc_abort()替代exit()
OpenACC专门提供了acc_abort()函数来处理设备端的程序终止需求,它会直接触发主机端的程序退出,效果和exit(1)几乎一样,而且编译器完全支持,不会有链接错误。
修改你的代码只需要两步:
- 包含OpenACC的头文件
<openacc.h> - 把
exit(1)替换成acc_abort(1)
修改后的代码:
#include <openacc.h> #include <stdlib.h> #include <math.h> // 假设你用到了isnan #pragma acc routine(Check) seq int Check (double **u, char *str) { for (int i = beg; i <= end; i++) { for (int v = 0; v < vend; v++) { if (isnan(u[i][v])) { #pragma acc routine(Here) seq Here (i,NULL); acc_abort(1); // 替换exit(1) } } } return 0; }
这个方案最简洁,完全符合OpenACC的规范,不用改动太多逻辑。
方案二:将错误状态传回主机端,由主机调用exit()
如果你因为某些原因不能用acc_abort(),可以在设备端设置一个错误标志,主机端同步后检查这个标志,再调用exit()。
比如:
- 定义一个错误标志变量,把它拷贝到设备端
- 修改
Check函数,在检测到错误时设置这个标志 - 主机端从设备端拷贝回标志,判断是否需要退出
示例代码:
#include <stdlib.h> #include <math.h> int error_flag = 0; // 全局错误标志,也可以用局部变量 #pragma acc routine(Check) seq int Check (double **u, char *str, int *err_flag) { for (int i = beg; i <= end; i++) { for (int v = 0; v < vend; v++) { if (isnan(u[i][v])) { #pragma acc routine(Here) seq Here (i,NULL); *err_flag = 1; // 设置设备端的错误标志 return 1; } } } return 0; } // 主机端调用示例 int main() { // ... 初始化u、beg、end等变量 #pragma acc enter data copyin(error_flag) // 将标志拷贝到设备端 #pragma acc parallel { Check(u, "NaN detected", &error_flag); } #pragma acc exit data copyout(error_flag) // 将标志拷贝回主机端 if (error_flag == 1) { exit(1); // 主机端调用exit } // ... 后续代码 return 0; }
最后再补充一句:exit()是操作系统提供的主机进程终止函数,GPU设备没有对应的系统调用支持,所以设备端代码根本没法直接调用它。必须要么用OpenACC提供的设备端终止函数,要么把终止逻辑移到主机端。
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

