如果发生破坏 CUDA 上下文的 CUDA 错误,则行为未定义。
这种类型的错误很明显,因为它是“粘性的”,这意味着一旦发生,每个 CUDA API 调用都会返回该错误,直到上下文被破坏。
非粘性错误在由 cuda API 调用返回后会自动清除(除了cudaPeekAtLastError
)。任何“内核崩溃”类型的错误(无效访问、未指定的启动失败等)都将是一个粘性错误。cudaMemcpy
在您的示例中,步骤 3 将(总是)在调用将变量 A 从设备传输到主机的结果上返回 API 错误,因此cudaMemcpy
操作的结果是未定义且不可靠的 - 就好像cudaMemcpy
操作在某些情况下也失败了未指定的方式。
由于损坏的 CUDA 上下文的行为是未定义的,因此没有定义任何分配的内容,或者通常是发生此类错误后的机器状态。
非粘性错误的一个示例可能是尝试cudaMalloc
获取比设备内存中可用的更多数据。这样的操作会返回一个内存不足的错误,但是该错误在返回后会被清除,并且后续(有效的)cuda API调用可以成功完成,而不会返回错误。非粘性错误不会破坏 CUDA 上下文,并且 cuda 上下文的行为与从未请求过无效操作完全相同。
粘滞错误和非粘滞错误之间的这种区别在许多记录在案的错误代码描述中都有体现,例如:
非粘性、非 cuda-context-corrupting:
cudaErrorMemoryAllocation = 2 API 调用失败,因为它无法分配足够的内存来执行请求的操作。
粘性,cuda-context-corrupting:
cudaErrorMisalignedAddress = 74 设备在未对齐的内存地址上遇到加载或存储指令。上下文不能被使用,所以它必须被销毁(并且应该创建一个新的)。此上下文中的所有现有设备内存分配都是无效的,如果程序要继续使用 CUDA,则必须重新构建。
请注意,cudaDeviceReset()
仅靠其本身不足以将 GPU 恢复到正确的功能行为。为了实现这一点,“拥有”过程也必须终止。见这里。