Коммуникаторы и группы. ранк потока
Группа - это некое множество ветвей. Одна ветвь может быть членом нескольких групп. В распоряжение программиста предоставлен тип MPI_Group и набор функций, работающих с переменными и константами этого типа. Констант, собственно, две: MPI_GROUP_EMPTY может быть возвращена, если группа с запрашиваемыми характеристиками в принципе может быть создана, но пока не содержит ни одной ветви; MPI_GROUP_NULL возвращается, когда запрашиваемые характеристики противоречивы. Согласно концепции MPI, после создания группу нельзя дополнить или усечь - можно создать только новую группу под требуемый набор ветвей на базе существующей. Коммуникатор, или описатель области связи - это верхушка трехслойного пирога (группы, области связи, описатели областей связи), вкоторый "запечены" задачи: именно с коммуникаторами программист имеет дело, вызывая функции пересылки данных, а также подавляющую часть вспомогательных функций.
Одной области связи могут соответствовать несколько коммуникаторов. Каждый поток в MPI имеет собственный номер, называемый рангом потока. Это число используется в большинстве функций передачи сообщений. Для получения своего ранга процесс может использовать функцию MPI_Comm_rank с двумя параметрами. Первый — коммуникатор, которому принадлежит данный процесс. В терминологии MPI коммуникатором называется группа потоков. Все потоки по умолчанию принадлежат коммуникатору MPI_COMM_WORLD, и нумерация идет с нуля. Программист может создавать собственные коммуникаторы и вводить в них собственную нумерацию. Второй параметр MPI_Comm_rank — это адрес, по которому будет записан ранг процесса. Для получения общего количества процессов в коммуникаторе используется функция MPI_Comm_size с такими же параметрами. Тут мы предполагаем, что ветвь 0 главная, а остальные управляются ею. Однако можно сделать и совсем по-другому, предоставляется полная свобода. Скелет MPI-программы
var p:pointer;
rank,size:integer;
begin
// не передаем параметры
p:=nil;
rank:=0;
MPI_Init(@rank,p);
MPI_Comm_rank(MPI_COMM_WORLD,@rank);
MPI_Comm_size(MPI_COMM_WORLD,@size);
if rank=0 then begin
// главнаяветвь
end else begin
// остальныеветви
end; MPI_Finalize(); end.
Напишите программу параллельного вычисления числа pi.
int main(int argc,char **argv)
{
int size,rank;
MPI_Status status;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&size);
floatn=500.0,a=0.0,s=0.0,r=0.0;
if(rank!=0) //в этом процессе вычисляем сумму четных чисел {
for(int i=0; i<n; i+=2)
{s+=4*(pow(-1,i)/(2*i+1));}
MPI_Send(&s,1,MPI_FLOAT,0,1,MPI_COMM_WORLD); }
if(rank==0) // в этом процессе вычисляем сумму нечетных чисел
{ for(int i=1; i<n; i+=2)
{s+=4*(pow(-1,i)/(2*i+1));}
MPI_Recv(&r,1,MPI_FLOAT,1,1,MPI_COMM_WORLD,&status); s+=r; // результат
printf("s=%f\n",s);}}
Сурак
1. Жарыс күйі. Синхронизация. Философтар есебі.
Состояние гонки — это ошибка, возникающая, когда результат программы зависит от того, какой из двух потоков первым достигнет определенного блока кода.
Необходимость синхронизации обуславливается тем обстоятельством, что не все возможные траектории совместно выполняемых потоков являются допустимыми .В самом общем виде, синхронизация может быть обеспечена при помощи задания необходимых логических условий, которые должны выполняться в соответствующих точках траекторий потоков. Задача обедающих философов.Задача позволяет рассмотреть способы доступа нескольких потоков к нескольким разделяемых ресурсов. Исходная формулировка задачи, впервые предложенная Э. Дейкстрой, выглядит следующим образом. Представляется ситуация, в которой пять философов располагаются за круглым столом.Для приема пищи в центре стола большое блюдо с неограниченным количеством спагетти, и тарелки, по одной перед каждым философом. Предполагается, что поесть спагетти можно только с использованием двух вилок. Для этого на столе располагается ровно пять вилок – по одной между тарелками философов.Для того, чтобы приступить к еде, философ должен взять вилки слева и, наложить спагетти, поесть, а затем обязательно положить вилки на свои места для их повторного использования. В данной задаче философы представляют собой потоки, а вилки – общие разделяемые ресурсы. Можно применить некоторое регламентирующее правило порядка взятия вилок – например, философ сначала берет левую вилку, затем правую. Итак, получаемый в результате алгоритм деятельности каждого философа состоит в следующем: как только философ приступает к еде, он пытается взять левую вилку. Если она занята, философ ждет ее освобождения и в конце концов ее получает. Возможная реализация предложенной схемы может состоять в следующем.
Semaphore fork[5] = { 1, 1, 1, 1, 1 };
Prilosopher(){// i – номер философа
while (1) { P(fork[i]); // Доступ к левой вилке P(fork[(i+1)%5]); // Доступ к правой вилке <Питание>
V(fork[i]); V(fork[(i+1)%5]) } }