OpenCL - c++包装器-动态库中的上下文取消初始化导致访问冲突

OpenCL - C++ wrapper - Context deinitialization in dynamic library leads to access violation

本文关键字:取消 上下文 初始化 访问冲突 包装 c++ 动态 OpenCL      更新时间:2023-10-16

我想构建一个库(windows系统上的共享库),它提供了一些默认配置(上下文,命令队列,…)。问题是,当应用程序试图退出时,会出现访问冲突。我的第一个猜测是,这可能是我的包装器实现的问题,但后来我建立了一个测试用例,使用官方的c++包装器(cl.hpp)。

在共享库中
boost::optional<cl::Context> cpuContext;
void cpu() {
    cpuContext = cl::Context(CL_DEVICE_TYPE_CPU);
}
应用端
int main(int argc, char** argv) {
    cpu();
}

非常简单的东西…

有趣的是,这种情况只发生在英特尔运行时(不能测试英特尔gpu),而不是Nvidia提供的运行时。如果在应用程序端声明了cpuContext变量,也不会发生这种情况。

我的问题是:
这是英特尔运行时的一个bug,还是我错过了一些东西,遇到了未定义的行为?

如果尝试从DllMain释放OpenCL对象,可能会出现一个非常微妙的问题。它可以显示您所看到的行为,但可能有些不可预测或断断续续。首先,简单介绍一下背景:

当你加载OpenCL.dll时,在大多数平台上,你正在加载一个标准化的可安装客户端驱动程序(ICD),它是你的代码和系统上可能存在的各种实现之间的一个垫片。你可以在这里读到更多。ICD是一个DLL,它使用Windows LoadLibrary调用来加载由OpenCL供应商(Intel, AMD等)提供的DLL。

使用LoadLibrary不会更新Windows DLL依赖跟踪结构。因此,当进程关闭时,无法知道这些dll被卸载的顺序。在这种情况下,当调用全局OpenCL上下文对象的析构函数时,供应商提供的OpenCL dll可能已经被卸载了。这有可能导致访问冲突。你可以在这里读到更多。

考虑到所有这些,我将避免设计需要在全局对象析构函数或DllMain中调用OpenCL函数的DLL。