Кластер - hpcource

реклама
Основы многопоточного программирования
Для сокращения времени, которое программа тратит на выполнение конкретной задачи, необходимо предпринять следующие действия:
1. определить возможность параллельных вычислений для выполнения конкретной задачи;
2. изменить задачу или создать специальный алгоритм для реализации параллельных вычислений;
3. запустить программу на ПК с несколькими процессорными элементами.
Ситуация, при которой изменение порядка обработки потоков влияет на производительность, называется "состоянием гонки" (race condition).
Классификация Флинна
Классы вычислительных систем
Симметричное мультипроцессирование (SMP)
Архитектура. Система состоит из нескольких однородных процессоров и массива
общей памяти. Все процессоры имеют достууп к любой точке памяти с одинаковой
скоростью. Процессоры подключены к памяти либо с помощью общей шины, либо
с помощью crossbar-коммутатора. Аппаратно поддерживается когерентность кешей.
Примеры: HP 9000 V-class, N-class; SMP-cервера и рабочие станции на базе
процессоров Intel (IBM, HP, Compaq, Dell, ALR, Unisys, DG, Fujitsu).
Масштабируемость. Наличие общей памяти сильно упрощает взаимодействие процессоров между собой, однако накладывает существенные
ограничения на их число – не более 32 в реальных системах.
Операционная система. Вся система работает под управлением единой ОС, которая автоматически распределяет процессы по процессорам.
Модель программирования .Программирование в модели общей памяти (POSIX threads, OpenMP).
Массивно-параллельные системы (MPP)
Архитектура. Система состоит из однородных вычислительных узлов, включающих один или несколько центральных процессоров, локальную память
(прямой доступ к памяти других узлов невозможен), коммуникационный процессор. К системе могут быть добавлены специальные узлы ввода-вывода
и управляющие узлы. Узлы связаны через некоторую коммуникационную среду.
Примеры: IBM RS/6000 SP2, Intel PARAGON/ASCI Red, CRAY T3E, Hitachi SR8000, транспьютерные системы Parsytec.
Масштабируемость. Общее число процессоров в реальных системах достигает нескольких тысяч (ASCI Red, Blue Mountain).
Операционная система. Полноценная ОС работает только на управляющей машине. На каждом узле работает сильно урезанный вариант ОС,
обеспечивающий только работу расположенной в нем ветви параллельного приложения.
Модель программирования. Программирование в рамках модели передачи сообщений (MPI, PVM, BSPlib).
Кластерные системы
Архитектура. Набор рабочих станций (или даже ПК) общего назначения использууется в качестве дешевого варианта массивно-параллельного
компьютера. Для связи узлов используется одна из стандартных сетевых технологий на базе шинной архитектуры или коммутатора.
Операционная система. На каждом узле работает стандартная для рабочих станций ОС вместе со специальными средствами поддержки параллельного
программирования и распределения нагрузки.
Модель программирования. Программирование в рамках модели передачи сообщений (MPI). Дешевизна подобных систем обуславливает большие
накладные расходы на взаимодействие параллельных процессов между собой, что сильно сужает класс решаемых задач.
Модели параллельных компьютеров
Параллельные компьютеры состоят из трех основных компонент: процессоры, модули памяти, и коммутирующая сеть.
Коммутирующая сеть соединяет процессоры друг с другом и иногда также с модулями памяти. Процессоры, используемые в параллельных
компьютерах, обычно точно такие же, что и процессоры однопроцессорных систем, хотя современная технология, позволяет разместить на микросхеме
не только один процессор. На микросхеме вместе с процессором могут быть расположены те компоненты или их составляющие, которые дают
наибольший эффект при параллельных вычислениях. Например, микросхема транспьютера наряду с 32-разрядным микропроцессором и 64-разрядным
сопроцессором плавающей арифметики содержит внутри кристальное ОЗУ емкостью 4Кбайт, 32-разрядную шину памяти, позволяющую адресовать до
4Гбайт внешней по отношению к кристаллу памяти, четыре последовательных двунаправленных линии связи, обеспечивающих взаимодействие
транспьютера с внешним миром и работающих параллельно с ЦПУ, интерфейс внешних событий.
Одним из свойств различающих параллельные компьютеры является число возможных потоков команд. Различают следующие архитектуры:

MIMD (Multiple Instruction Multiple Data - множество потоков команд и множество потоков данных). MIMD компьютер
имеет N процессоров, Nпотоков команд и N потоков данных. Каждый процессор функционирует под управлением собственного потока
команд.

SIMD (Single Instruction Multiple Data - единственный поток команд и множество потоков данных). SIMD компьютер имеет N идентичных
синхронно работающих процессоров, N потоков данных и один поток команд. Каждый процессор обладает собственной локальной памятью.
Сеть, соединяющая процессоры, обычно имеет регулярную топологию.
Другим свойством, различающим параллельные компьютеры, является способ доступа к модулям памяти, то есть имеет ли каждый процессор
локальную память и обращается к другим блокам памяти, используя коммутирующую сеть, или коммутирующая сеть соединяет все процессоры с
общей памятью. Исходя из способа доступа к памяти, различают следующие (довольно условные) типы параллельных (MIMD) архитектур:
Компьютеры с распределенной памятью (Distributed memory)
Каждый процессор имеет доступ только к локальной собственной памяти. Процессоры объединены в сеть. Доступ к удаленной памяти
возможен только с помощью системы обмена сообщениями.
Компьютеры с общей (разделяемой) памятью (True shared memory)
Каждый процессор компьютера обладает возможностью прямого доступа к общей памяти, используя общую шину (возможно,
реализованную на основе высокоскоростной сети). В таких компьютерах нельзя существенно увеличить число процессоров, поскольку при
этом происходит резкое увеличение числа конфликтов доступа к шине.
В некоторых архитектурах каждый процессор имеет как прямой доступ к общей памяти, так и собственную локальную память.
Компьютеры с виртуальной общей (разделяемой) памятью (Virtual shared memory)
В таких системах общая память как таковая отсутствует. Каждый процессор имеет собственную локальную память. Он может обращаться к
локальной памяти других процессоров, используя "глобальный адрес". Если "глобальный адрес" указывает не на локальную память, то
доступ к памяти реализуется с помощью сообщений с малой задержкой, пересылаемых по сети, соединяющей процессоры.
Отметим два класса компьютерных систем, которые иногда используются как параллельные компьютеры:


локальные вычислительные сети (LAN), в которых компьютеры находятся в физической близости и соединены быстрой сетью,
глобальные вычислительные сети (WAN), которые соединяют географически распределенные компьютеры.
SSE (Streaming SIMD Extensions) - расширение инструкций процессора для потоковой обработки в режиме SIMD (Single Instruction Multiple Data), т.е.
когда требуется применять однотипные операции к потоку данных.
Расширение SSE разработано компанией Intel и было впервые применено в процессоре Intel Pentium III с ядром Katmai. Отсюда изначальное название
KNI (Katmai New Instructions). Технология SSE позволила преодолеть проблемы MMX - при использовании MMX невозможно было одновременно
использовать инструкции сопроцессора, так как его регистры задействовались для MMX и работы с вещественными числами.
SSE включает в архитектуру процессора восемь 128-битных регистров и набор инструкций, работающих со скалярными и упакованными типами
данных.
Преимущество в производительности достигается в том случае, когда необходимо произвести одну и ту же последовательность действий над разными
данными. В таком случае блоком SSE осуществляется распараллеливание вычислительного процесса между данными.
Особенности





8 (в x86-64 - 16)128-битных регистров XMM.
32-битный (в x86-64 - 64) регистр флагов (MXCSR).
128-битный упакованный тип данных с плавающей точкой одинарной точности.
Инструкции над вещественными числами одинарной точности.
Инструкции явной предвыборки данных, контроля кэширования данных и контроля порядка операций сохранения.
Регистры
В SSE добавлены восемь (шестнадцать) 128-битных регистров, которые называются xmm0 — xmm7 (-xmm15).
Каждый регистр может содержать четыре 32-битных значения с плавающей точкой одинарной точности.
Для запуска программ в UNIX используются два системных вызова – fork() и exec().
fork() — системный вызов, создающий новый (дочерний) процесс, идентичный выполняющему этот вызов. После вызова fork() алгоритм обычно
разветвляется (родительский процесс получает от fork() значение PID дочернего процесса, а дочерний получает нуль).
После fork() дочерний процесс чаще всего выполняет системный вызов exec(), загружающий в пространство процесса новую программу (именно так, и
только так, в UNIX выполняется запуск программы в отдельном процессе). Так, первый (нулевой) процесс UNIX (ядро системы) создаёт свою копию,
чтобы запустить init (процесс с PID = 1), который в свою очередь создаёт дочерние процессы для запуска инициализации системы и терминалов.
При завершении работы программа (дочерний процесс) выполняет системный вызов exit(), при этом родительский процесс с помощью системного
вызова wait() (или waitpid()) должен очистить таблицы планировщика процессов от информации о своем дочернем процессе. Если этого не происходит
и родительский процесс завершается, не вызвав wait() для всех своих дочерних процессов, в системе возникают зомби (zombie), представляющие собой
записи в таблицах планировщика процессов. Очистить операционную систему от зомби можно только с помощью перезагрузки.
Демонами в мире Unix традиционно называются процессы, которые не взаимодействуют с пользователем напрямую. У процесса-демона нет
управляющего терминала и нет, соответственно, пользовательского интерфейса. Для управления демонами приходится использовать другие
программы. Само название «демоны» возникло благодаря тому, что многие процессы этого типа большую часть времени проводят в ожидании какогото события. Когда это событие наступает, демон активизируется, выполняет свою работу и снова засыпает в ожидании события. Следует отметить, что
многие демоны, такие как, например, Web-сервер или сервер баз данных, могут отбирать на себя практически все процессорное время и другие ресурсы
системы. Такие демоны гораздо больше работают, чем спят.
Процесс-сирота — в семействе операционных систем UNIX вспомогательный процесс, чей основной процесс был завершен нештатно.
Обычно, «сиротой» остается дочерний процесс после неожиданного завершения родительского, но возможно возникновение сервера-сироты при
неожиданном прерывании связи или завершении клиентского процесса.
Процессы-сироты расходуют системные ресурсы сервера и могут быть источником проблем. Существует несколько их решений:



Уничтожение — наиболее часто используется, заключается в немедленном завершении процесса
Перевоплощение — система пытается «воскресить» родителей в состоянии на момент перед их удалением или найти других родителей.
Выдача лимита времени — процессу выдаётся временная квота для завершения до момента, когда он будет «убит» принудительно. Отметим,
что процессу оставлена возможность запросить дополнительное время для завершения.
В Unix-подобных системах все процессы-сироты немедленно усыновляются специальным системным процессом «init».
Зомби - процесс получивший это состояние, завершился раньше, чем этого ожидал его родительский процесс. Обычно освобождение структур ядра,
относящихся к процессу, выполняет процесс-родитель после получения от потомка сигнала о завершении. Если процесс-родитель или init по каким-то
причинам не может принять сигнал о завершении дочернего процесса, то процесс-потомок превращается в "зомби" и получает статус Z. Процессызомби не занимают процессорного времени (т. е. их выполнение прекращается), но соответствующие им структуры ядра не освобождаются. В
некотором смысле это «мертвые» процессы. Уничтожение таких процессов — одна из обязанностей системного администратора. Хочу отметить, что
появление данных процессов говорит о том, что в системе что-то не в порядке, и скорее всего не в порядке с аппаратной частью.
Для многопоточного программирования наиболее широко используется интерфейс OpenMP* и такие библиотеки, как pthreads (для ОС Unix) и
Windows* threads.
Библиотека OpenMP представляет собой набор управляющих команд и процедур для многопоточного программирования, можно также использовать
для формирования очередей задач и многопоточных вычислений на более высоком уровне. При использовании этой библиотеки основное время
тратится на организацию циклов и управляющих команд для компилятора, который должен распределить циклы между потоками. Простота является
основным достоинством OpenMP: библиотека включает несколько управляющих команд, которые не меняют семантики базовой программы. Кроме
того, OpenMP дает возможность из программы с последовательными вычислениями постепенно создать программу с параллельными вычислениями,
контролируя работоспособность приложения на каждом этапе программирования.
Описание возможностей технологии OpenMP.
• Технология OpenMP позволяет в максимальной степени эффективно реализовать возможности многопроцессорных вычислительных систем с общей
памятью, обеспечивая использование общих данных для параллельно выполняемых потоков без каких-либо трудоемких межпроцессорных передач
сообщений.
• Сложность разработки параллельной программы с использованием технологии OpenMP в значительной степени согласуется со сложностью
решаемой задачи – распараллеливание сравнительно простых последовательных программ, как правило, не требует больших усилий (порою
достаточно включить в последовательную программу всего лишь несколько директив OpenMP) это позволяет, в частности, разрабатывать
параллельные программы и прикладным разработчикам, не имеющим большого опыта в параллельном программировании.
• Технология OpenMP обеспечивает возможность поэтапной (инкрементной) разработки параллельных программы – директивы OpenMP могут
добавляться в последовательную программу постепенно (поэтапно), позволяя уже на ранних этапах разработки получать параллельные программы,
готовые к применению; при этом важно отметить, что программный код получаемых последовательного
Под параллельной программой в рамках OpenMP понимается программа, для которой в специально указываемых при помощи директив местах –
параллельных фрагментах– исполняемый программный код может быть разделен на несколько раздельных командных потоков (threads). Важно
отметить, что разделение вычислений между потоками осуществляется под управлением соответствующих директив OpenMP. Равномерное
распределение вычислительной нагрузки – балансировка (load balancing) – имеет принципиальное значение для получения максимально
возможного ускорения выполнения параллельной программы. Потоки могут выполняться на разных процессорах (процессорных ядрах) либо могут
группироваться для исполнения на одном вычислительном элементе (в этом случае их исполнение осуществляется в режиме разделения времени). В
предельном случае для выполнения параллельной программы может использоваться один процессор – как правило, такой способ применяется для
начальной проверки правильности параллельной программы. Количество потоков определяется в начале выполнения параллельных фрагментов
программы и обычно совпадает с количеством имеющихся вычислительных элементов в системе; изменение количества создаваемых потоков может
быть выполнено при помощи целого ряда средств OpenMP. Все потоки в параллельных фрагментах программы последовательно перенумерованы от 0
до np-1, где np есть общее количество потоков. Номер потока также может быть получен при помощи функции OpenMP.
Использование в технологии OpenMP потоков для организации параллелизма позволяет учесть преимущества многопроцессорных вычислительных
систем с общей памятью. Прежде всего, потоки одной и той же параллельной программы выполняются в общем адресном пространстве, что
обеспечивает возможность использования общих данных для параллельно выполняемых потоков без каких-либо трудоемких межпроцессорных передач
сообщений (в отличие от процессов в технологии MPI для систем с распределенной памятью). И, кроме того, управление потоками (создание,
приостановка, активизация, завершение) требует меньше накладных расходов для ОС по сравнению с процессами.
Библиотеки с поддержкой явной многопоточности использовать гораздо труднее. Они содержат функции, в которых записаны потоки с исполняемыми
кодами. В нужном месте программы с помощью специальной функции происходит разветвление потоков. Для создания потоков и написания их кода
требуется разработка дополнительного кода, вот почему многопоточные библиотеки сложны в обращении и могут привести к ошибкам в программе. В
отличие от библиотек OpenMP, для которых нужен специальный компилятор, для работы с многопоточными прикладными программными
интерфейсами необходимо предусмотреть лишь связь с многопоточными библиотеками. То есть многопоточные прикладные программные интерфейсы
поддерживают больше компиляторов и языков программирования.
закон Амдала
Правило, которое определяет влияние на прирост производительности, называется
законом Амдала. Рассмотрим задачу:
T(c ) - полное решение задачи. Разделим общее время на два интервала: в
параллельные вычисления - (fp), последовательные - (fs). При увеличении количества
процессоров в системе сократится время только параллельных вычислений, при этом
зависимость общего времени выполнения программы (Т) от количества процессоров
(Р) будет выглядеть следующим образом:
T(P) = (fs + fp/P)T(s) = (fs + (1-fs)/P)T(s)
Кластер.
Кластер – множество отдельных компьютеров, объединенных в сеть. Ключевые особенности:
– отсутствие общей памяти
– пересылка данных по сети
‰Кластеры стали фактическим стандартом высокопроизводительных систем. Основные достоинства:
– дешевизна
– простая расширяемость
Кластеры, как правило, используются одновременно большим числом пользователей.
Вычислительные задачи очень требовательны к ресурсам и работают днями и даже неделями.
Необходимы специализированные системы, способные эффективно управлять ресурсами кластера.
Наиболее часто используемые сетевые интерфейсы: Gigabit Ethernet, Myrinet
Наиболее распространенные процессоры – Intel . Наиболее распространенное количество ядер ‐ 2
Как построить кластер
‰Обратиться в специальную компанию: "Т‐платформы", Kraftway, IBM, HP, …или
‰Собрать самому «кластер рабочих станций» (cluster of workstations):
– Несколько компьютеров, купленных в обычном магазине, без монитора, без графической карты, часто без жесткого диска
– Сеть (Gigabit Ethernet, Myrinet, InfiniBand…)
– Качественный коммуникатор
– Выделенный управляющий компьютер, файловое хранилище
– Система охлаждения
или
‰Получить доступ к действующему кластеру
Программное обеспечение кластера
‰В качестве операционной системы на кластерах используют различные версии ОС Unix и Linux (в сумме более 90%
операционных систем списка top500)
‰В последнее время увеличивается число кластеров на базе ОС Windows (6 установок в текущем списке top500)
‰MPI – наиболее распространенная коммуникационная библиотека
Программное обеспечение кластера
‰Помимо интерфейса передачи сообщений необходимо специально ПО для управления потоком задач потоком задач
‰Два основных подхода к управлению кластерами:
1. Распределенные окружения для кластерных вычислений
2. Системы управления кластерами
‰Идея первого подхода состоит в создании «кластерной» операционной системы
+ Подобные среды весьма удобны, работа в них фактически не отличается от работы в обычной операционной системе
– Необходима коррекция операционной системы. Существуют реализации только для UNIX‐подобных операционных систем.
‰Системы управления кластерами работают поверх операционной системы.
Они являются развитием систем пакетной обработки.
‰Система управления кластером Condor была создана группой разработчиков университета Висконсин‐Мэдисон
. Первая конфигурация была развернута в этом университете университете вв 1986 1986 году году
‰Ключевые особенности системы:
– Создание контрольных точек с возможностью миграции контрольных точек с возможностью миграции
заданий между процессами
– Возможность интеграции в интеграции в Grid
– Поддержка широкого круга архитектур и операционных систем
– Использование для вычислений не только выделенных машин, но и рабочих станций
Типы узлов в системе:
– Центральный менеджер. Ядро системы. Собирает информацию о загрузке узлов кластера и получает
запросы пользователей, он затем определяет время и место запуска.Остановка менеджера приведет к остановке всей системы
– Выполняющие машины. Счетные узлы. Производительность выполняющих машин в конечном итоге
определяет, когда пользователь получит результат. Однако , Condor создавался с намерением использовать все
доступные ресурсы, в том числе и низкопроизводительные
Семафор — это механизм синхронизации, который можно использовать для управления отношениями между параллельно выполняющимися программными
компонентами и реализации стратегий доступа к данным. Семафор — это переменная специального вида, которая может быть доступна только для выполнения узкого
диапазона операций. Семафор используется для синхронизации доступа процессов и потоков к разделяемой модифицируемой памяти или для управления доступом к
устройствам или другим ресурсам.
Как упоминалось выше, к семафору можно получить доступ только с помощью специальных операций, подобных тем, которые выполняются с объектами. Это операции
декремента, P(), и инкремента, V(). Если объект Mutex представляет собой семафор, то логика реализации операций P (Mutex) и V (Mutex) м ожет выглядеть
таки м образо м:
P(Mutex)
if (Mutex > 0) {
Mutex--;
} else {
Блокирование по объекту Mutex;
}
V(Mutex)
if(Oчepeдь доступа к объекту Mutex не пуста){
Передача объекта Мьютекс следующей задаче;
} else {
Mutex++;
}
Реализация зависит от конкретной систе м ы. Эти операции неделимы, т.е. их невозможно прервать. Если операцию P () попытаются выполнить сразу несколько задач, то
лишь одна из них получит разрешение продолжить работу. Если объектMutex был уже декре м ентирован, то задача будет заблокирована и зай м ет м есто в очереди.
Операци я V () вызываетс язадачей, которая и м еет доступ к объекту Mutex.
Если получения доступа к объекту Мьютекс ожидают дру г ие задачи, он «передается » следующей задаче из очереди. Если очередь задач пуста,
объект Mutex инкрементируетс я.
Операции с семафором могут иметь другие имена:
Операци я P(): lock()
Операци я V(): unlock()
Значение семафора зависит от его типа. Двоичный семафор будет иметь значение 0 или 1. Вычислительный семафор(определяю щ ий лимиты ресурсов для процессов,
получающих доступ к ним) может иметь некоторое неотрицательное целочисленное значение.
Стандарт POSIX определяет несколько типов семафоров. Эти семафоры испо л ьзуются процессами или потоками. Типы семафоров (а также их некоторые основные
операции) перечислены в табл. 5.1.
Таблица 5 .1. Типы семафоров, определенные стандартом POSIX
Тип семафора
Пользователь
Описание
Мьютексный семафор
Процессы или
потоки
Механизм, используемый для реализации взаимного исключения в критическом разделе кода
Блокировка для обеспечения чтения и
записи
Процессы или
потоки
Механизм, используемый для реализации стратегии доступа для чтения и записи среди потоков
Условная переменная
Процессы или
потоки
Механизм, используемый для уведомления потоков о том, что произошло событие.
Событийный мьютекс остается заблокированным потоком до тех пор, пока не будет получен
соответствующий сигнал
Несколько условных переменных
Процессы или
потоки
Аналогичен событийному мьютексу, но включает несколько событий или условий
Мьютексные семафоры
Стандарт POSIX определяет мьютексный семафор, используемый потоками и процессами, как объект типа pthread_mutex_t. Этот мьютекс обеспечивает базовые
операции, необходимые для функционирования практического механизма синхронизации:
• инициализация;
• запрос на монопольное использование;
• отказ от монопольного использования;
• тестирование монопольного использования;
• разрушение.
Функции класса pthread_mutex_t, которые используются для выполнения этих базовых операций, перечислены в табл. 5.2. Во время инициализации выделяется память,
необходимая для функционирования мьютексного семафора, и объекту семафора присваивается некоторое начальное значение. Для двоичного семафора начальным
может быть значение 0 или 1. Начальным значением вычислительного семафора может быть неотрицательное число, которое представляет количество доступных
ресурсных единиц. Семафорное значение можно использовать для представления предельного количества запросов, которое способна обработать программа в одном
сеансе. В отличие от обычных переменных, в инициализации которых сомневаться не приходится, факт инициализации мьютекса с помощью вызова соответствующей
функции гарантировать невозможно. Чтобы убедиться в том, что мьютекс проинициализирован, необходимо после вызова операции инициализации принять некоторые
меры предосторожности (например, проверить значение, возвращаемое соответствующей мьютекс-ной функцией, или значение переменной errno). Системе не удастся
создать мьютекс, если окажется, что занята память, предусмотренная ранее для мьютексов, или превышено допустимое количество семафоров, или семафор с данным
именем уже существует, или же имеет место какая-то другая проблема, связанная с выделением памяти.
Таблица 5.2. Функции класса pthread_mutex_t
Инициализация int pthread_mutex_init( pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex =PTHREAD_MUTEX_INITIALIZER;
Запрос на монопольное использование #include <pthread.h>
<time.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex,
const struct timespec *restrict abs_timeout);
Отказ от монопольного использо вания int pthread_mutex_unlock(pthread_mutex_t *mutex);
Тестирование монопольно г о использования int pthread_mutex_trylock(pthread_mutex_t *mutex);
Разрушение int pthread_mutex_destroy(
pthread_mutex_t *mutex);
Самый большой интерес представляет установка атрибута, связанного с тем, каким должен быть мьютекс: закрытым или разделяемым. Закрытые мьютексы
разделяются между потоками одного процесса. Можно либо объявить мьютекс глобальным, либо организовать передачу дескриптора между
потоками. Разделяемые мьютексы используются потоками, имеющими доступ к памяти, в которой размещен данный мьютекс. Такой мьютекс могут разделять потоки
различных процессов. Если разделять мьютекс приходится потокам различных процессов, его необходимо разместить в памяти, которая является общей для этих
процессов. В библиотеке POSIX определено несколько функций, предназначенных для распределения памяти между объектами с помощью отображаемых в памяти
файлов и объектов разделяемой памяти. В процессах мьютексы можно использовать для защиты критических разделов, которые получают доступ к файлам, каналам,
общей памяти и внешним устройствам.
Скачать