Многозадачное и многопоточное программирование в WINDOWS
Автор работы: Пользователь скрыл имя, 12 Декабря 2012 в 20:49, курсовая работа
Описание работы
Цель работы: Изучить способы и средства написания параллельно выполняющихся процессов и потоков средствами языка C++ в операционных системах семейства Windows.
Проект может быть реализован на Visual C++ 6.0 или в среде Borland C++ 5.0. В первом случае выбирается консольное приложение Win32 без дополнительных библиотек. Во втором случае в программу необходимо добавить файл включения windows.h.
Содержание работы
1. Цель работы. ………………………………………….3
2. Методические указания. …………………………….3
3. Порядок выполнения работы. ……………………....4
4. Задание. ……………………………………………….5
5. Практическая часть
5.1 Код программы………………………………………………. 6
5.2 Описание программы…………………………………...............7
5.3 Теоретический вопрос…………….........................................10
5.4 Список литературы………………………………………..…..17
Файлы: 1 файл
Курсовая на распечатку.docx
— 36.71 Кб (Скачать файл)Белорусский Национальный Технический Университет
Международный Институт Дистанционного Образования
Курсовая работа
по дисциплине: «Системное программное обеспечение»
на тему: «Многозадачное и многопоточное
программирование в WINDOWS».
Подготовил ст.гр. 417429/15
Билык Александр
Проверил: Дадыкин А.К.
Минск 2012
Содержание:
- Цель работы. ………………………………………….
3
2. Методические указания. …………………………….3
3. Порядок выполнения работы. ……………………....4
4. Задание. ……………………………………………….5
5. 5.1 Код программы………………………………………………. 6
5.2Описание программы…………………………………........
5.3 Теоретический вопрос……………...................
5.4 Список литературы………………………………………..…..
- Цель работы: Изучить способы и средства написания параллельно выполняющихся процессов и потоков средствами языка C++ в операционных системах семейства Windows.
- Методические указания.
Проект может быть реализован на Visual C++ 6.0 или в среде Borland C++ 5.0. В первом случае выбирается консольное приложение Win32 без дополнительных библиотек. Во втором случае в программу необходимо добавить файл включения windows.h.
Выбор функции для ожидания завершения порожденных процессов (потоков) зависит от логики работы программы, определяемой вариантом задания.
Уничтожение порожденных процессов (потоков) применяется лишь в тех вариантах, где это действительно необходимо.
Для обмена информацией между процессами рекомендуется использовать файлы. При использовании потоков для обмена информацией целесообразно использовать глобальные переменные.
- Порядок выполнения работы.
- Написать и отладить программу, реализующую порожденный процесс.
- Написать и отладить программу, реализующую родительский процесс, вызывающий и отслеживающий состояние порожденных процессов (ждущий их завершения или уничтожающий их, в зависимости от варианта).
- Написать и отладить программу, реализующую родительский процесс, вызывающий и отслеживающий состояние порожденных потоков (функций) (ждущий их завершения или уничтожающий их, в зависимости от варианта).
4. Задание.
Вариант 15.
- Число генерируется по истечению случайного времени. Получение числа реализуется в порожденном процессе (потоке). Количество чисел определяется случайно в диапазоне от 3 до 10. Найти сумму всех чисел.
- Реализация функций API на уровне системы программирования. Особенности.
6.1. Листинг программы.
// threads.cpp: определяет точку входа для консольного приложения.
//
#include "stdafx.h"
#include "iostream"
#include <conio.h>
#include <Windows.h>
#include <ctime>
#include <conio.h>
using namespace std;
#define N_TS 10
DWORD seed, summ;
DWORD WINAPI GEN_NUM()
{
/*int g,a;
srand((unsigned)time);
g=rand()%100;
cout<<g<<endl;
return summ+=g;*/
DWORD a;
seed ^= 0xDEADC0DE;
seed = (seed >> 16) | (seed << 16);
seed -= GetTickCount();
seed *= 0xE9192939;
summ += a = (seed % 9 + 1);
cout << "Number:" << a << endl;
return ( seed % 9 + 1 );
}
int main ()
{
int x;
srand( GetTickCount() );
x = 3 + rand() % 10;
DWORD r;
HANDLE hThreads[ 10 ];
HANDLE hMutex;
hMutex = CreateMutex(NULL, FALSE, NULL);
cout << "This is program for searching sum numbers which generation for random time" << endl;
cout << "For started press any button..." << endl;
_getch();
Cout << "Generation random number of value threads and value numbers" << endl << "for their sum:";
cout<< x << "\t(range number- 3..10)" << endl << endl;
for(int i = 0; i < x; i++)
{
hThreads[ i ] = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE)GEN_
}
for(int i = 0;i <= x;i++)
{
int seed;
seed ^= 0xDEADC0DE;
seed = (seed >> 16) | (seed << 16);
seed -= GetTickCount();
seed *= 0xE9192939;
r = WaitForMultipleObjects(i, hThreads, FALSE, (seed % 9 + 1));
if(seed < 0)
{
seed*=-1;
}
else r = WaitForMultipleObjects(i, hThreads, FALSE, ((seed % 9 + 1) * 1000));
summ =+ summ;
}
_getch();
ReleaseMutex(hMutex);
cout<<"Result:"<<endl<<"Summ - "<<summ<<endl;
cout<<"For exit press any button...";
_getch();
return 0;
}
Описание программы:
Программа написана в среде разработки Microsoft Visual Studio 2010, для платформы Win32(консольное приложение). Для реализации многопоточности использовались функции WinApi. WinApi - это набор функций для создания программ, работающих под управлением Windows. Вначале программы мы генерируем случайное число, которое будет определять количество созданных потоков, а следовательно и количество функций потоков, которые они будут обрабатывать.
Первая функция из WinApi которая нам встречается это функция GetTickCount(). Она определяет количество времени пошедшее с начала запуска системы и возвращает это значение. С помощью это функции нам удаётся сгенерировать случайные числа при каждом обращении к ней.
Для того чтобы мы могли пользоваться потоками мы должны создать объект типа HANDLE. Если необходим массив объектов, то количество элементов массива должно быть константным. Созданный объект порождает основной поток с помощью функции CreateThread(), который в свою очередь порождает дочерние потоки(их количество мы определили случайно).
Когда созданы потоки нужно синхронизировать их работу чтобы избежать неразберихи вызванной одновременным обращением нескольких потоков к одной функции. Чтобы этого избежать можно применять различные средства синхронизации(мьютексы, семафоры, события, таймеры и т.д.), но в моей программе синхронизация происходит посредством мьютексов. Мьютексы это объекты ядра гарантирующие потокам взаимоисключающий доступ к единственному ресурсу. Кроме счетчика пользователей мьютекс содержит счетчик рекурсии и переменную, в которой запоминается идентификатор потока-владельца. Чтобы создать мьютекс один из процессов должен создать его вызовом HANDLE CreatMutex().
С помощью потока вывода cout в консоли отображается необходимая информация, которая говорит о действиях выполняемых программой, а функция _getch() приостанавливает работу программы до нажатия любой клавиши и из-за этого вывод информации последователен и читабелен.
После этого создаётся i потоков функцией CreateThread(). Эта функция содержит свои параметры: LPSECURITY_ATTRIBUTES threadAttributes- атрибуты доступа ,DWORD dwStackSize- размер стека, LPTHREAD_START_ROUTINE "IpStartAddress- адрес функции потока ,LPVOID IpParameter-параметр функции потока,DWORD dwCreationFlags- флаги потока,LPDWORD IpThreadld - идентификатор потока. Для многих параметров можно задавать значения по умолчанию 0 или NULL. Третий параметр не может иметь значение по умолчанию, ему всегда передается адрес функции потока. Четвертый параметр часто используется для организации взаимосвязи вызывающего потока с дочерним потоком.
После создания массива потоков идёт цикл for в котором после генерации случайных чисел для четвёртого параметра функции WaitForMultipleObjects() задаётся время которое должен ожидать поток чтобы передать управление следующему потоку. Функция имеет следующий прототип: DWORD WaitForMultipieObjects(DWORD nCount. CONST HANDLE* lpHandles,BOOL fWaitAll. DWORD dwMi11iseconds); Она работает так же, как и функция WaitForSingleObject, но при этом позволяет
ждать освобождения сразу нескольких объектов или какого-то одного объекта из заданного списка. Параметр nCount определяет количество интересующих вас объектов ядра. Его значение должно быть в пределах от 1 до MAXIMUM_WAIT_OBJECTS. В заголовочных файлах Windows эта константа имеет значение 64. Параметр lpHandles содержит указатель на массив дескрипторов объектов ядра. В массиве могут содержаться
дескрипторы объектов разных типов. Параметр fWaitAll определяет поведение функции. Значение TRUE задает режим ожидания освобождения всех указанных объектов, a FALSE — только одного из них. В последнем случае код возврата функции содержит информацию о том, какой именно объект освободился. Возвращаемое функцией значение сообщает, почему возобновилось выполнение вызвавшего ее потока. Значения AIT_TIMEOUT и WAIT_FAILED интерпретируются по аналогии с функцией WaitForSingleObject. Если параметр fWaitAll равен TRUE и все объекты перешли в свободное состояние, то функция возвращает значение
WAIT_OBJECT_0. Если же fWaitAll имеет значение FALSE, то функция возвращает управление, как только освобождается любой из объектов. При этом ее код возврата лежит в интервале от WAIT_OB0ECT_O до WAIT_OBJECT_0 + nCount - 1.
Далее управление передаётся потокам по отдельности, а они в свою очередь работают с созданной функцией GEN_NUM, которая имеет тип DWORD WINAPI и генерирует случайные числа и возвращает результат.
После обработки функции программа начинает удалять созданные потоки. Также и удаляет созданный объект ядра – мьютекс. Мьютекс удаляется при вызове функции RealeseMutex(). Есть и другие способы как можно проделать эту операцию, но эти способы зависят от конкретной ситуации и не всегда бывают приемлемы.
В конце программы выводится результат, а именно сумма всех сгенерированных случайных чисел функцией GEN_NUM и приглашение на завершение программы, которое срабатывает после нажатия любой клавиши.
6.2. Теоретический вопрос.
Реализация функций API на уровне системы программирования. Особенности.
API (application program interface, интерфейс прикладного программирования) на следующие направления:
• API как интерфейс высокого уровня, принадлежащий к библиотекам RTL;
• API прикладных и системных программ, входящих в поставку операционной системы;
• прочие API.
Интерфейс прикладного программирования, как это и следует из названия, предназначен для использования прикладными программами системных ресурсов ОС и реализуемых ею функций. API описывает совокупность функций и процедур, принадлежащих ядру или надстройкам ОС.
API представляет собой набор функций, предоставляемых системой программирования разработчику прикладной программы и ориентированных на организацию взаимодействия результирующей прикладной программы с целевой вычислительной системой. Целевая вычислительная система представляет собой совокупность программных и аппаратных средств, в окружении которых выполняется результирующая программа. Сама результирующая программа порождается системой программирования на основании кода исходной программы, созданного разработчиком, а также объектных модулей и библиотек, входящих в состав системы программирования.
Функции API также используется для многих системных программ как в составе ОС, так и в составе системы программирования.
Функции API позволяют разработчику строить результирующую прикладную программу так, чтобы использовать средства целевой вычислительной системы для выполнения типовых операций. При этом разработчик программы избавлен от необходимости создавать исходный код для выполнения этих операций.
Программный интерфейс API включает в себя не только сами функции, но и соглашения об их использовании, которые регламентируются операционной системой (ОС), архитектурой целевой вычислительной системы и системой программирования.
Существует несколько вариантов реализации API:
• реализация на уровне ОС;
• реализация на уровне системы программирования;
• реализация на уровне внешней библиотеки процедур и функций.
Система программирования в каждом из этих вариантов предоставляет разработчику средства для подключения функций API к исходному коду программы и организации их вызовов. Объектный код функций API подключается к результирующей программе компоновщиком при необходимости.
Возможности API можно оценивать со следующих позиций:
• эффективность выполнения функций API — включает в себя скорость выполнения функций и объем вычислительных ресурсов, потребных для их выполнения;
• широта предоставляемых возможностей;
• зависимость прикладной программы от архитектуры целевой вычислительной системы.
Добиться наивысшей эффективности выполнения функций API практически трудно по тем же причинам, по которым невозможно добиться наивысшей эффективности выполнения для любой результирующей программы. Поэтому об эффективности API можно говорить только в сравнении его характеристик с другим API.
Что касается двух других показателей, то в принципе нет никаких технических ограничений на их реализацию. Однако существуют организационные проблемы и узкие корпоративные интересы, тормозящие создание такого рода библиотек.
Реализация функций API на уровне системы программирования.
Если функции API реализуются на уровне системы программирования, они предоставляются пользователю в виде библиотеки функций соответствующего языка программирования. Обычно речь идет о библиотеке времени исполнения — RTL (run time library). Система программирования предоставляет пользователю библиотеку соответствующего языка программирования и обеспечивает подключение к результирующей программе объектного кода, ответственного за выполнение этих функций.
Очевидно, что эффективность функций API в таком варианте будет несколько ниже, чем при непосредственном обращении к функциям ОС. Так происходит, поскольку для выполнения многих функций API библиотека RTL языка программирования должна все равно выполнять обращения к функциям ОС. Наличие всех необходимых вызовов и обращений к функциям ОС в объектном коде RTL обеспечивает система программирования.
Однако переносимость исходного кода программы в таком варианте будет самой высокой, поскольку синтаксис и семантика всех функций будут строго регламентированы в стандарте соответствующего языка программирования. Они зависят от языка и не зависят от архитектуры целевой вычислительной системы. Поэтому для выполнения прикладной программы на новой архитектуре вычислительной системы достаточно заново построить код результирующей программы с помощью соответствующей системы программирования.