Камерон Хьюз - Параллельное и распределенное программирование на С++
- Название:Параллельное и распределенное программирование на С++
- Автор:
- Жанр:
- Издательство:Издательский дом «Вильямс»
- Год:2004
- Город:МоскваСанкт-ПетербургКиев
- ISBN:ISBN 5-8459-0686-5 (рус.)ISBN 0-13-101376-9 (англ.)
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Камерон Хьюз - Параллельное и распределенное программирование на С++ краткое содержание
Эта книга адресована программистам, проектировщикам и разработчикам программных продуктов, а также научным работникам, преподавателям и студентам, которых интересует введение в параллельное и распределенное программирование с использованием языка С++.
Параллельное и распределенное программирование на С++ - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Параллельно выполняемые процессы (или потоки в одном процессе) могут совместно использовать структуры данных, переменные или отдельные данные. Разделение глобальной памяти позволяет процессам или потокам взаимодействовать друг с другом и получать доступ к общим данным. При использовании нескольких процессов разделяемая глобальная память является внешней по отношению к ним. Внешнюю структуру данных можно использовать для передачи данных или команд между процессами. Если же необходимо организовать взаимодействие потоков, то они могут иметь доступ к структурам данных или переменным, являющимся частью одного и того же процесса, которому они принадлежат.
Если существуют процессы или потоки, которые получают доступ к разделяемым модифицируемым данным, структурам данных или переменным, то все эти данные находятся в критической области (или разделе) кода процессов или потоков. Критический раздел кода — это та его часть, в которой обеспечивается доступ потока или процесса к разделяемому блоку модифицируемой памяти и обработка соответствующих данных. Отнесение раздела кода к критическому можно использовать для управления состоянием «гонок». Например, создаваемые в программе два потока, поток А и поток В, используются для поиска нескольких ключевых слов во всех файлах системы. Поток А просматривает текстовые файлы в каждом каталоге и записывает нужные пути в списочную структуру данных TextFiles,а затем инкрементирует переменную FileCount.Поток В выделяет имена файлов из списка TextFiles,декрементирует переменную FileCount,после чего просматривает файл на предмет поиска в нем заданных ключевых слов. Файл, который их содержит, переписывается в другой файл, и инкрементируется еще одна переменная FoundCount.К переменной FoundCountпоток А доступа не имеет. Потоки А и В могут выполняться одновременно на отдельных процессорах. Поток А выполняется до тех пор, пока не будут просмотрены все каталоги, в то время как поток В просматривает каждый файл, путь к которому выделен из переменной TextFiles.Упомянутый список поддерживается в отсортированном порядке, и в любой момент его содержимое можно отобразить на экране.
Здесь возможна масса проблем. Например, поток В может попытаться выделить имя файла из списка TextFilesдо того, как поток А его туда поместит. Поток В может попытаться декрементировать переменную SearchCountдо того, как поток А её инкрементирует, или же оба потока могут попытаться модифицировать эту переменную одновременно. Кроме того, во время сортировки элементов списка TextFilesпоток А может попытаться записать в него имя файла, или поток В будет в это время пытаться выделить из него имя файла для выполнения своей задачи. Описанные проблемы—это примеры условий «гонок», при которых несколько потоков (или процессов) пытаются одновременно модифицировать один и тот же блок общей памяти.
Если потоки или процессы одновременно лишь читают один и тот же блок памяти, условия «гонок» не возникают. Они возникают в случае, когда несколько процессов или потоков одновременно получают доступ к одному и тому же блоку памяти, и по крайней мере один из этих процессов или потоков делает попытку модифицировать данные. Раздел кода становится критическим, когда он делает возможными одновременные попытки изменить один и тот же блок памяти. Один из способов защитить к ритический раздел — разрешить только монопольный доступ к блоку памяти. Монопольный доступ означает, что к разделяемому блоку памяти будет иметь доступ один процесс или поток в течении короткого промежутка времени, при этом всем остальным процессам или потокам запрещено (путем блокировки) входить в свои критические разделы, которые обеспечивают доступ к тому же самому блоку памяти.
Для управления условиями «гонок» можно использовать такой механизм блокировки, как взаимо - исключающий семафор, или мьютекс (mutex— сокращение от «mutual exclusion», - взаимное исключение). Мьютекс используется для блокирования критического раздела: он блокируется до входа в критический раздел, а при выходе из него - деблокируется:
Блокирование мьютекса
// Вход в критический раздел.
// Доступ к разделяемой модифицируемой памяти.
// Выход из критического раздела.
Деблокирование мьютекса
Класс pthread_mutex_tпозволяет смоделировать мьютексный объект. Прежде, чем объект типа pthread_mutex_tможно будет использовать, его необходимо инициализировать. Для инициализации мьютекса используется функция pthread_mutex_init().Инициализированный мьютекс можно заблокировать деблокировать и разрушить с помощью функций pthread_mutex_lock(), pthread_mutex_unlock() и pthread_mutex_destroy() соответственно. В программе 4.5 содержится функция, которая выполняет поиск текстовых файлов, а в программе 4.6 — функция, которая просматривает каждый текстовый файл на предмет содержания в нем заданных ключевых слов. Каждая функция выполняется потоком. Основной поток реализован в программе 4.7. Эти программы реализуют модель «изготовитель-потребитель» для делегирования задач потокам. Программа4.5 содержит поток-«изготовитель», а программа 4.6 — поток-«потребитель». Критические разделы выделены в них полужирным шрифтом.
// Программа 4.5
1 int isDirectory(string FileName)
2 {
3 struct stat StatBuffer;
4
5 lstat(FileName.c_str(),&StatBuffer);
6 if((StatBuffer.st_mode & S_IFDIR) == -1)
7 {
8 cout << «could not get stats on file» << endl;
9 return(0);
10 }
11 else{
12 if(StatBuffer.st_mode & S_IFDIR){
13 return(1);
14 }
15 }
16 return(0);
17 }
18
19
20 int isRegular(string FileName)
21 {
22 struct stat StatBuffer;
23
24 lstat(FileName.c_str(),&StatBuffer);
25 if((StatBuffer.st_mode & S_IFDIR) == -1)
26 {
27 cout << «could not get stats on file» << endl;
28 return(0);
29 }
30 else{
31 if(StatBuffer.st_mode & S_IFREG){
32 return(1);
33 }
34 }
35 return(0);
36 }
37
38
39 void depthFirstTraversal(const char *CurrentDir)
40 {
41 DIR *DirP;
42 string Temp;
43 string FileName;
44 struct dirent *EntryP;
45 chdir(CurrentDir);
46 cout << «Searching Directory: " << CurrentDir << endl;
47 DirP = opendir(CurrentDir);
48
49 if(DirP == NULL){
50 cout << «could not open file» << endl;
51 return;
52 }
53 EntryP = readdir(DirP);
54 while(EntryP != NULL)
55 {
56 Temp.erase();
57 FileName.erase();
58 Temp = EntryP->d_name;
59 if((Temp != ".») && (Temp != "..»)){
60 FileName.assign(CurrentDir);
Интервал:
Закладка: