Лабораторная работа 4 (Сортировка Бэтчэра (Ясенков))

Посмотреть архив целиком

Московский Энергетический Институт

(Технический Университет)

Кафедра Прикладной Математики

Отчет по лабораторной работе 4


Выполнил: Ясенков Е.М.

Группа: А-13-03

Москва 2008


Реализовать параллельный алгоритм сортировки Бэтчэра. Элементами массива являются структуры, для которых определены отношения «>» и «<». Предполагается, что необъодимо сортировать большой массив данных.


Для распараллеливания алгоритма используется технология OpenMP.

This document specifies a collection of compiler directives, library functions, and environment variables that can be used to specify shared-memory parallelism in C and C++ programs. The functionality described in this document is collectively known as the OpenMP C/C++ Application Program Interface (API). The goal of this specification is to provide a model for parallel programming that allows a program to be portable across shared-memory architectures from different vendors. The OpenMP C/C++ API will be supported by compilers from numerous vendors. More information about OpenMP, including the OpenMP Fortran Application Program Interface, can be found at the following web site:


The directives, library functions, and environment variables defined in this document will allow users to create and manage parallel programs while permitting portability. The directives extend the C and C++ sequential programming model with single program multiple data (SPMD) constructs, work-sharing constructs, and synchronization constructs, and they provide support for the sharing and privatization of data. Compilers that support the OpenMP C and C++ API will include a command-line option to the compiler that activates and allows interpretation of all OpenMP compiler directives.

This specification covers only user-directed parallelization, wherein the user explicitly specifies the actions to be taken by the compiler and run-time system in order to execute the program in parallel. OpenMP C and C++ implementations are not required to check for dependencies, conflicts, deadlocks, race conditions, or other problems that result in incorrect program execution. The user is responsible for ensuring that the application using the OpenMP C and C++ API constructs executes correctly. Compiler-generated automatic parallelization and directives to the compiler to assist such parallelization are not covered in this document.

OpenMP uses the fork-join model of parallel execution. Although this fork-join model can be useful for solving a variety of problems, it is somewhat tailored for large array-based applications. OpenMP is intended to support programs that will execute correctly both as parallel programs (multiple threads of execution and a full OpenMP support library) and as sequential programs (directives ignored and a simple OpenMP stubs library). However, it is possible and permitted to develop a program that does not behave correctly when executed sequentially. Furthermore, different degrees of parallelism may result in different numeric results because of changes in the association of numeric operations. For example, a serial addition reduction may have a different pattern of addition associations than a parallel reduction. These different associations may change the results of floating-point addition.

A program written with the OpenMP C/C++ API begins execution as a single thread of execution called the master thread. The master thread executes in a serial region until the first parallel construct is encountered. In the OpenMP C/C++ API, the parallel directive constitutes a parallel construct. When a parallel construct is encountered, the master thread creates a team of threads, and the master becomes master of the team. Each thread in the team executes the statements in the dynamic extent of a parallel region, except for the work-sharing constructs. Work-sharing constructs must be encountered by all threads in the team in the same order, and the statements within the associated structured block are executed by one or more of the threads. The barrier implied at the end of a work-sharing construct without a nowait clause is executed by all threads in the team.

If a thread modifies a shared object, it affects not only its own execution environment, but also those of the other threads in the program. The modification is guaranteed to be complete, from the point of view of one of the other threads, at the next sequence point (as defined in the base language) only if the object is declared to be volatile. Otherwise, the modification is guaranteed to be complete after first the modifying thread, and then (or concurrently) the other threads, encounter a flush directive that specifies the object (either implicitly or explicitly). Note that when the flush directives that are implied by other OpenMP directives are not sufficient to ensure the desired ordering of side effects, it is the programmer's responsibility to supply additional, explicit flush directives.

Upon completion of the parallel construct, the threads in the team synchronize at an implicit barrier, and only the master thread continues execution. Any number of parallel constructs can be specified in a single program. As a result, a program may fork and join many times during execution.

The OpenMP C/C++ API allows programmers to use directives in functions called from within parallel constructs. Directives that do not appear in the lexical extent of a parallel construct but may lie in the dynamic extent are called orphaned directives. Orphaned directives give programmers the ability to execute major portions of their program in parallel with only minimal changes to the sequential program. With this functionality, users can code parallel constructs at the top levels of the program call tree and use directives to control execution in any of the called functions.

Unsynchronized calls to C and C++ output functions that write to the same file may result in output in which data written by different threads appears in nondeterministic order. Similarly, unsynchronized calls to input functions that read from the same file may read data in nondeterministic order. Unsynchronized use of I/O, such that each thread accesses a different file, produces the same results as serial execution of the I/O functions


#include "stdafx.h"

#include "iostream"


#ifndef _OPENMP


struct elem


elem () { x = 0; };

elem(double arg) { x = arg; };

double x;

bool operator > (elem el2) { return x > el2.x; }


void swap(elem& p1, elem& p2)


elem temp = p1;

p1 = p2;

p2 = temp;


int main(int argc, char** argv)


if(argc < 2)


std::cout<<"Wrong number of arguments"<

return 0;


// Готовим матрицу для сортировки

int n = atoi(argv[1]);

elem* pA = new elem[n];

for(int i=0; i

double start_time = GetTickCount();

// Устанавливаем начальные значения

int t = log((double)n)/log(2.0);

int p = pow(2.0, (double)(t-1));

while(p > 0)


int q = pow(2.0, (double)(t-1));

int r = 0;

int d = p;

while(q >= p)


int nCurrSize = (n - d);

// Инициализируем все процессы и запускаем их

#pragma omp parallel for

for(int i=0; i pA[d + i]) swap(pA[i], pA[d + i]);

d = q-p;

q = q/2;



p = p/2;



return 0;



В качестве тестовой задачи использовалась сортировка больших массивов данных (10000000 – 50000000 объектов) на процессоре Intel Core2 Duo 6300 частота – 1.86, ОС - Windows XP.

Диаграмма зависимости времени вычислений от количества потоков

Диаграмма зависимости ускорения вычислений от количества потоков и размерности задачи


Применение потоков OpenMP для распараллеливания циклов в данной задачи на многоядерных процессорах позволяет стабильно повысить производительность на 65%. Данная технология является очень легкой в использовании и освоении.