Нить строительный блок в сочетании с нитями

У меня есть очередь с элементами, которые нужно обработать. Я хочу обрабатывать эти элементы параллельно. В каждом элементе будет несколько разделов, которые необходимо синхронизировать. В любой момент времени может быть максимум num_threads бегущие темы.

Я предоставлю шаблон чтобы дать вам представление о том, чего я хочу достичь.

queue q

process_element(e)
{
lock()
some synchronized area
// a matrix access performed here so a spin lock would do
unlock()
...
unsynchronized area
...
if( condition )
{
new_element = generate_new_element()
q.push(new_element) // synchonized access to queue
}
}

process_queue()
{
while( elements in q ) // algorithm is finished condition
{
e = get_elem_from_queue(q) // synchronized access to queue
process_element(e)
}
}

я могу использовать

  • Pthreads
  • OpenMP
  • строительные блоки Intel

Основные проблемы, которые у меня есть

  • Убедитесь, что в любой момент времени у меня есть максимум num_threads бегущие потоки
  • Облегченные методы синхронизации для использования в очереди

Мой план в отношении Intel TBB concurrent_queue для контейнера очереди. Но тогда я смогу использовать функции pthreads (мьютексы, условия)? Давайте предположим, что это работает (это должно). Тогда как я могу использовать pthreads, чтобы иметь максимальное количество num_threads в один момент времени? Я думал создать потоки один раз, а затем, после того, как один элемент — процессы, получить доступ к очереди и получить следующий элемент. Однако это более сложно, потому что я не могу гарантировать, что если в очереди нет элемента, алгоритм завершен.

Мой вопрос

Прежде чем я начну внедрять, я хотел бы знать, есть ли простой способ использовать intel tbb или pthreads для получения желаемого поведения? Точнее параллельно обрабатывать элементы из очереди

Замечания: Я пытался использовать задачи, но безуспешно.

1

Решение

Во-первых, pthreads дает вам мобильность, от которой трудно уйти. Следующее представляется верным из вашего вопроса — дайте нам знать, если это не так, потому что ответ изменится:
1) У вас есть многоядерный процессор (ы), на котором вы выполняете код
2) хочешь иметь не больше чем num_threads темы из-за (1)

Предполагая, что вышеизложенное верно, следующий подход может вам помочь:

  1. Создайте num_threads pthreads используя pthread_create
  2. При желании, привязать каждый поток к другому ядру
  3. q.push (new_element) атомарно добавляет new_element в очередь. pthreads_mutex_lock и pthreads_mutex_unlock могут помочь вам здесь. Примеры здесь: http://pages.cs.wisc.edu/~travitch/pthreads_primer.html
  4. Используйте pthreads_mutexes для удаления элементов из очереди
  5. Завершение является хитрым — один из способов сделать это — добавить элемент TERMINATE в очередь, что при снятии очереди заставляет разветвитель ставить в очередь другой элемент TERMINATE (для следующего разветвителя) и затем завершается. В итоге у вас будет один дополнительный элемент TERMINATE в очереди, который вы можете удалить, оставив именованным потоком в очереди его после завершения всех потоков.

В зависимости от того, как часто вы добавляете / удаляете элементы из очереди, вы можете использовать что-то более легкое, чем pthread_mutex _…, чтобы ставить в очередь / исключать из очереди элементы. Здесь вы можете использовать более специфичную для машины конструкцию.

1

Другие решения

TBB совместим с другими пакетами потоков.

TBB также подчеркивает масштабируемость. Поэтому, когда вы переносите свою программу с двухъядерного на четырехъядерное ядро, вам не нужно настраивать свою программу. При параллельном программировании данных производительность программы увеличивается (масштабируется) по мере добавления процессоров.

Cilk Plus — это еще одна среда выполнения, которая обеспечивает хорошие результаты.

www.cilkplus.org

Поскольку pThreads является низкоуровневой ведущей библиотекой, вам нужно решить, какой уровень управления вам нужен в вашем приложении, потому что он предлагает гибкость, но требует больших затрат с точки зрения усилий программиста, времени отладки и затрат на обслуживание.

0

Я рекомендую посмотреть на tbb::parallel_do, Он был разработан для параллельной обработки элементов из контейнера, даже если сам контейнер не является параллельным; то есть parallel_do работает с std::queue правильно без какой-либо пользовательской синхронизации (конечно, вам все равно нужно защитить свой матричный доступ внутри process_element(), Более того, с parallel_do Вы можете добавить больше работы на лету, которая выглядит как то, что вам нужно, а process_element() создает и добавляет новые элементы в рабочую очередь (единственное предупреждение заключается в том, что вновь добавленная работа будет обработана немедленно, в отличие от помещения в очередь, которая откладывает обработку до всех «старых» элементов). Кроме того, вам не нужно беспокоиться о прекращении: parallel_do завершится автоматически, как только будут обработаны все начальные элементы очереди и новые элементы, созданные на лету.

Однако если, помимо самих вычислений, рабочую очередь можно одновременно передавать из другого источника (например, из потока обработки ввода / вывода), тогда parallel_do не подходит. В этом случае, возможно, имеет смысл взглянуть на parallel_pipeline или, лучше, график потока TBB.

Наконец, приложение может контролировать количество активных потоков с помощью TBB, хотя это не рекомендуемый подход.

0
По вопросам рекламы [email protected]