спецификацию.
На самом деле, схемой master-worker дело не ограничивается. Я попробовал смоделировать задачу обедающих философов. На C++ я пишу не слишком хорошо, но код все равно выложу в качестве примера странного использования OpenMP.
Задача звучит достаточно просто: имеется круглый стол, тарелка спагетти, пять философов вокруг стола и 5 вилок, распределенных между каждой парой соседей-философов. При этом философ может находится в двух состояниях - философ есть и философ думает. Философы народ странный и могут есть только в том случае, если возьмут в руки сразу две вилки (правую и левую). Когда философ не ест - он думает. Требуется смоделировать задачу таким образом, чтобы ни один философ не голодал (вечно переходил из состояния "думает" в "ест" и наоборот) при условии, что философы не могут общаться друг с другом.
Самый простой способ добиться отсутствия взаимоблокировок - присвоить каждой вилке номер (0 до 5) и ввести правило: философ сначала берет вилку с меньшим номером, а затем с большим. Класть же вилки на стол он должен в обратном порядке - сначала с большим номером, а затем с меньшим. Т.е для первых четверых философов алгоритм будет следующим - сначала берется правая вилка, затем левая. А вот для пятого все меняется: сначала берется левая, а затем правая. Такой подход не даст пятому философы взять последнюю оставшуюся на столе вилку, если остальные уже разобрали, и ее сможет взять первый философ, что позволит ему приступить к еде а затем вилки освободить. Этот способ, конечно, далеко не эффективен, но очень прост в реализации и понимании.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "omp.h"
#define PHILO_COUNT 5
#define FORKS_COUNT 5
omp_lock_t forks[FORKS_COUNT];
void think(int i) {
int secs = 1 + (rand() % PHILO_COUNT);
printf("Философ %d думает %d секунд...\n", i, secs);
sleep(secs);
}
void eat(int i) {
int fork_first;
int fork_second;
if (i == PHILO_COUNT - 1) {
fork_first = 0;
fork_second = i;
} else {
fork_first = i;
fork_second = i + 1;
}
printf("Философ %d просит вилку (%d)\n", i, fork_first);
omp_set_lock(&forks[fork_first]);
printf("Философ %d просит вилку (%d)\n", i, fork_second);
omp_set_lock(&forks[fork_second]);
//симуляция процесса поедания пищи
int secs = rand() % PHILO_COUNT;
printf("Философ %d ест %d секунд\n...", i, secs);
omp_unset_lock(&forks[fork_second]);
omp_unset_lock(&forks[fork_first]);
}
void simulation(int i) {
while (true) {
think(i);
eat(i);
}
}
int main() {
srand(time(NULL));
omp_set_num_threads(PHILO_COUNT);
for (int i = 0; i < PHILO_COUNT; i++) {
omp_init_lock(&forks[i]);
}
#pragma omp parallel for private(i)
for (int i = 0; i < PHILO_COUNT; i++) {
simulation(i);
}
return 0;
}
Возможно, в будущем в код будут внесены какие-нибудь изменения, поэтому лучше посмотреть на мой гитхаб.
Comments
comments powered by Disqus