Мне нужно запустить несколько потоков 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 и связать его с обработчиком событий. Затем поток может дождаться окончания события. Не уверен, что это работает, хотя в многопоточной ситуации …
Главный вопрос заключается в том, нужно ли всем этим потокам использовать одно и то же ядро или каждый из них получает свое собственное ядро. Ваша идея использовать либо объекты thread_local cl_kernel, либо массив из n объектов ядра, приводит к созданию n объектов ядра и одинаково хорошо с точки зрения OpenCL. Однако, если все они содержат один и тот же код, то вы излишне тратите пространство / вызываете переключение контекста / портите кеширование / … и это было бы сравнимо с загрузкой двоичного файла приложения в память несколько раз без разделения сегментов постоянного двоичного кода.
Если вы действительно хотите использовать одно и то же ядро в нескольких потоках, я бы посоветовал выполнить синхронизацию вручную для одного объекта cl_kernel. Если вы не хотите, чтобы ваши потоки блокировали ожидание до тех пор, пока другие потоки не завершили свою работу, вы можете использовать асинхронную очередь команд и события, чтобы получать уведомления, когда работа определенного потока завершена (чтобы не допустить работу потока в очереди быстрее, чем GPU может) обработайте это или прочитайте результаты конечно).
Если ваши потоки будут выполнять разные программы ядра, тогда я предлагаю создать отдельную очередь команд для каждого потока, чтобы упростить выполнение. Это полностью зависит от вас, если вы решили хранить эти дескрипторы объектов в локальном хранилище потока, в глобальном массиве или в другом месте.
Других решений пока нет …