C++11: thread_local или массив объектов OpenCL 1.2 cl_kernel?
Мне нужно запустить несколько потоков C++11 (GCC 4.7.1) параллельно на хосте. Каждый из них должен использовать устройство, скажем, графический процессор. Согласно спецификации OpenCL 1.2 (стр. 357):
All OpenCL API calls are thread-safe75 except clSetKernelArg.
clSetKernelArg is safe to call from any host thread, and is safe
to call re-entrantly so long as concurrent calls operate on different
cl_kernel objects. However, the behavior of the cl_kernel object is
undefined if clSetKernelArg is called from multiple host threads on
the same cl_kernel object at the same time.
Изящным способом было бы использовать объекты thread_local cl_kernel, а другой способ, который я могу придумать, - это использовать массив этих объектов, чтобы i-й поток использовал i-й объект. Поскольку я не реализовал их ранее, мне было интересно, если какой-либо из этих двух вариантов хорош или есть лучшие способы добиться своей цели.
Третий способ - использовать мьютекс для одного cl_object и связать его с обработчиком событий. Затем поток может дождаться окончания события. Не уверен, что это работает, хотя в многопоточной ситуации...
1 ответ
Главный вопрос заключается в том, нужно ли всем этим потокам использовать одно и то же ядро или каждый из них получает свое собственное ядро. Ваша идея использовать либо объекты thread_local cl_kernel, либо массив из n объектов ядра, приводит к созданию n объектов ядра и одинаково хорошо с точки зрения OpenCL. Однако, если все они содержат один и тот же код, то вы излишне тратите пространство / вызываете переключение контекста / портите кеширование /... и это было бы сравнимо с загрузкой двоичного файла приложения в память несколько раз без разделения постоянных сегментов двоичного кода.
Если вы действительно хотите использовать одно и то же ядро в нескольких потоках, я бы посоветовал выполнить синхронизацию вручную для одного объекта cl_kernel. Если вы не хотите, чтобы ваши потоки блокировали ожидание до тех пор, пока другие потоки не завершили свою работу, вы можете использовать асинхронную очередь команд и события, чтобы получать уведомления после завершения работы определенного потока (чтобы не допустить, чтобы поток в очереди работал быстрее, чем GPU может) обработайте это или прочитайте результаты конечно).
Если ваши потоки будут выполнять разные программы ядра, тогда я предлагаю создать отдельную очередь команд для каждого потока, чтобы упростить выполнение. Тогда полностью ли это зависит от вас, если вы решили хранить эти дескрипторы объектов в локальном хранилище потока, в глобальном массиве или где-либо еще.