Параллельное и распределенное программирование на С++
Шрифт:
// Листинг 4.7. Подход 2: скелет программы реализации . модели управляющего и рабочих потоков
pthread_t Thread[N]
// boss thread
{
pthread_create(&(Thread[1]...taskX...);
pthread_create(&(Thread[2]...taskY...);
pthread_create(&(Thread[3]...taskZ...);
//...
loop while(Request Queue is not empty
get request
classify request
switch(request type)
{
case X :
enqueue request to XQueue
signal Thread[1]
case Y :
enqueue request to YQueue
signal Thread[2]
case Z :
enqueue request to ZQueue
signal Thread[3]
//...
}
end loop
}
void *taskX(void *X)
{
loop
suspend until awaken by boss
loop while XQueue is not empty
dequeue request
process request
end loop
until done
{
void *taskY(void *Y)
{
loop
suspend until awaken by boss
loop while YQueue is not empty
dequeue request
process request
end loop
until done
}
void *taskZ(void *Z)
{
loop
suspend until awaken by boss
loop while (ZQueue is not empty)
dequeue request
process request
end loop
until done
} //.. .
В
Использование модели сети с равноправными узлами
В модели равноправных узлов один поток сначала создает все потоки, необходимые выполнения всех задач. Каждый из равноправных потоков обрабатывает запросы, поступающие из собственного входного потока данных. В листинге 4.8 представлен скелет программы, реализующий при разделении программы на потоки метод равноправных узлов
Листинг 4.8. Скелет программы реализации модели равноправных потоков
pthread_t Thread[N]
// initial thread
{
pthread_create(&(Thread[1]...taskX...);
pthread_create(&(Thread[2]...taskY...);
pthread_create(&(Thread[3]...taskZ...);
//...
}
void *taskX(void *X)
{
loop while (Type XRequests are available)
extract Request
process request
end loop
return(NULL)
}
В
Использование модели конвейера
В модели конве йера поток входных данных обрабатывается поэтапно. На каждом этапе некоторая порция работы (часть входного потока данных) обрабатывается одним потоком выполнения, а затем передается для обработки следующему. Каждая порция входных данных переходит на очередной этап обработки до тех пор, пока не будет завершена вся обработка. Такой подход позволяет обрабатывать несколько входных потоков данных одновременно. Каждый поток выполнения отвечает за достижение пром ежуточного результата, делая его доступным для следующего этапа (т.е. следующего потока конвейера). Скелет программы реализации модели конвейера представлен в листинге 4.9.
// Листинг 4.9. Скелет программы реализации модели конвейера
//...
pthread_t Thread[N]
Queues[N]
// initial thread
{
place all input into stage1's queue
pthread_create(&(Thread[1]...stage1...);
pthread_create(&(Thread[2]...stage2...);
pthread_create(&(Thread[3]...stage3...);
//...
}
void *stageX(void *X)
{
loop
suspend until input unit is in queue
loop while XQueue is not empty
dequeue input unit
process input unit
enqueue input unit into next stage's queue
end loop
until done
return(NULL)
}
В листинге 4.9 объявляется N очередей для N этапов. Начальный поток помещает все порции входных потоков в очередь первого этапа, а затем создает все потоки, необходимые для выполнения всех этапов. Каждый этап содержит свой цикл событий. Поток выполнения находится в состоянии ожидания до тех пор, пока в его очереди не появится порция входных данных. Внутренний цикл продолжается до опустения соответствующей очереди. Порция входных данных извлекается из очереди, обрабатывается, а затем помещается в очередь следующего этапа обработки (следующего потока выполнения).
Использование модели «изготовитель-потребитель»
В модели «изготовитель-потребитель» поток- «изготовитель» готовит данные, «потребляемые» потоком-«потребителем» (причем таких потоков-«потребителей" может быть несколько). Данные хранятся в блоке памяти, разделяемом всеми потока, как изготовителем, так и потребителями. В листинге 4.10 представлен скелет программы реализации модели «изготовитель-потребитель» (эта модель также использовалась в программах 4.5, 4.6 и 4.7).