Оболочки C ++ для OpenCL используют подсчет ссылок, предоставляемый собственным API OpenCL (см. clRetainMemObject
и clReleaseMemObject
для отслеживания каждого буфера). Возможно, было бы правильно думать о них, как о том, что они реализованы примерно так:
class cl::Buffer {
cl_mem buffer;
public:
Buffer(/*...*/) { buffer = clCreateBuffer(/*...*/);} //Implicit Retain
Buffer(Buffer const& o) {buffer = o.buffer; clRetainMemObject(buffer);}
~Buffer() {clReleaseMemObject(buffer);}
/*...*/
};
Это также относится и к подбуферам: они используют тот же механизм подсчета внутренних ссылок, что и основной буфер (clCreateSubBuffer
неявно указывает на вызов retain для объекта , создающего буфер), поэтому он будет быть также подсчитанным по ссылке и оставаться действительным до тех пор, пока остается владелец объекта, удерживая ссылку и на исходный буферный объект.
Этот код может помочь:
cl::Buffer do_stuff() {
cl::Buffer buffer{context, CL_MEM_READ_WRITE, 1000};
std::cout << "Ref Count: " << buffer.getInfo<CL_MEM_REFERENCE_COUNT>() << std::endl;
//Should print "Ref Count: 1" to console
cl::Buffer copy = buffer; //retain
std::cout << "Ref Count: " << buffer.getInfo<CL_MEM_REFERENCE_COUNT>() << std::endl;
//Should print "Ref Count: 2"
std::cout << "Ref Count: " << copy.getInfo<CL_MEM_REFERENCE_COUNT>() << std::endl;
//Should print "Ref Count: 2"
cl_buffer_region reg={20, 50};
cl::Buffer sub = buffer.createSubBuffer(CL_MEM_READ_WRITE, CL_BUFFER_CREATE_TYPE_REGION, ®); //retain
std::cout << "Ref Count: " << buffer.getInfo<CL_MEM_REFERENCE_COUNT>() << std::endl;
//Should print "Ref Count: 3"
std::cout << "Ref Count: " << sub.getInfo<CL_MEM_REFERENCE_COUNT>() << std::endl;
//I believe it prints "Ref Count: 1", but if it inherits the main buffer's reference count,
//then it'll print "Ref Count: 3" instead. Not sure what the actual specification is
return sub;
//release buffer
//release copy
}
void outer_code() {
cl::Buffer subBuffer = do_stuff();
//Should print "Ref Count: 1", "Ref Count: 2", "Ref Count: 2", "Ref Count: 3", "Ref Count: 1", in order
std::cout << "Ref Count: " << subBuffer.getInfo<CL_MEM_REFERENCE_COUNT>() << std::endl;
//Should print "Ref Count: 1"
//End of scope: release subBuffer
}
Мы также можем подтвердить, что, используя семантику сохранения / выпуска, исходный буфер не будет удален до тех пор, пока также не будут удалены подпуферы, потому что спецификация гласит:
После того, как счетчик ссылок memobj
станет равным нулю и команды будут поставлены в очередь для выполнения на
Очереди команд, использующих memobj
, завершены, объект памяти удален. Если memobj
является буферным объектом, memobj
не может быть удалено до тех пор, пока не будут удалены все объекты подбуфера, связанные с memobj. Использование этой функции для освобождения ссылки, которая не была получена при создании объекта или с помощью вызов clRetainMemObject
вызывает неопределенное поведение
- clReleaseMemObject , спецификация OpenCL 2.0, стр. 156
Таким образом, в предположении, что C ++ OpenCL Wrapper реализован правильно, тогда можно с уверенностью сказать, что подпуфер сохранится после того, как вы удалили владельца для исходного объекта буфера, потому что оригинал будет удален с помощью команды retain / Освободить семантику и, таким образом, поддерживать до тех пор, пока не будет удален суббуфер.