Параллельные вычисления – способ организации компьютерных вычислений, при котором программы разрабатываются как набор взаимодействующих вычислительных процессов, работающих параллельно (одновременно).
С точки зрения операционной системы существуют 2 основных способа реализации параллельных вычислений: многозадачность и многопоточность.
Многозадачность означает, что каждый вычислительный процесс может быть реализован в виде процесса операционной системы
Многопоточность – это свойство операционной системы или приложения, состоящее в том, что процесс, порождённый в операционной системе, может состоять из нескольких потоков, выполняющихся по независимому пути исполнения, одновременно с другими потоками.
Многопоточность не следует путать ни с многозадачностью, ни с многопроцессорностью, несмотря на то, что операционные системы, реализующие многозадачность, как правило реализуют и многопоточность.
Многопоточность применяется во многих программах, поскольку при выполнении некоторых задач разделение процесса на потоки помогает достичь более эффективного использования ресурсов вычислительной машины.
При создании многопоточных приложений необходимо контролировать взаимодействие отдельных потоков. Большинство ошибок при работе с потоками возникает из-за того, что во время работы приложения различные потоки пытаются обратиться к одним и тем же данным. Для предотвращения подобной ситуации в ОС Windows (и в других операционных системах) существуют средства синхронизации, которые позволяют контролировать доступ к разделяемым ресурсам.
Средства синхронизации ОС Windows включают такие методы взаимодействия потоков, как взаимоисключения (мьютексы), семафоры, критические секции и события.
Приложение, обладающее возможностью наглядной демонстрации работы различных методов синхронизации нескольких потоков, было бы полезно начинающим программистам для более полного и глубокого понимания принципов работы многопоточного приложения, однако существует небольшое количество таких программных продуктов.
В связи с вышеуказанной проблемой была предпринята попытка написания программы с удобным пользовательским интерфейсом и возможностью изучения каждого из методов синхронизации.
В качестве языка программирования был выбран C#, так как платформа .Net Framework и язык C# предоставляют удобные встроенные средства для реализации следующих блокировок:
• синхронизирующая блокировка Lock;
• синхронизирующая блокировка Monitor;
• синхронизация с помощью класса Mutex;
• синхронизация с помощью класса Semaphore;
• синхронизация с помощью класса Event.
Алгоритм работы программы основан на увеличении значения общей переменной десятью различными потоками, выполняющимися одновременно.
Для реализации алгоритма были созданы следующие классы:
Counter – класс, в котором не используется синхронизация;
CounterLock – класс, в котором используется метод синхронизации Lock();
CounterMonitor – класс, в котором используется метод синхронизации Monitor();
CounterMutex – класс, в котором используется метод синхронизации Mutex();
CounterSemaphore – класс в котором используется метод синхронизации Semaphore();
CounterEvent – класс в котором используется метод синхронизации Event().
Каждый класс имеет 2 переменные:
int _count – инкриментируемая переменная;
int _evenCount – количество четных чисел из всех _count.
Также каждый класс имеет 1 метод void UpdateCount(), который увеличивает переменные _count и _evenCount и применяет соответствующую блокировку.
В программе были созданы следующие методы:
void UpdateCount(object param);
void UpdateCountLock(object param);
void UpdateCountMonitor(object param);
void UpdateCountMutex(object param);
void UpdateCountSemaphore(object param);
void UpdateCountEvent(object param).
Каждый из этих методов создает класс с соответствующей блокировкой и увеличивает в нем переменные _count и _evenCount в диапазоне от [a,b]. Где a, b – глобальные переменные, задающие диапазон изменения переменных _count и _evenCount.
Для организации вычислений в программе используются обработчики кнопок, использующие описанные выше классы и методы. Каждый метод создает 10 потоков одновременно изменяющих значение общей переменной _count. Результаты вычислений выводятся на форму.
В приложении необходимо задать диапазон значений, в котором может изменяться переменная count. По умолчанию значения переменной count изменяются в диапазоне от 0 до 100 000.
В однопроцессорной (одноядерной) системе многопоточный код выдаст результат, равный произведению 100 000 на число потоков.
При выполнении программы на многопроцессорной (многоядерной) системе без блокировки полученный результат будет отличаться от заданного значения (рис. 1).
Рис. 1. Выполнение программы без применения блокировки
Несоответствие заданному значению происходит из-за механизма обновления переменной count процессором. Этот код выполняется в 3 этапа:
1. Значение переменной помещается в регистр процессора.
2. В регистре это значение увеличивается.
3. Значение копируется из регистра в память.
При многопоточной обработке все три этапа выполняются как атомарные операции. В этом случае сразу несколько потоков могут считывать и обновлять значения в памяти, поэтому в приложении не выполняется часть операций.
При выполнении программы с включенной блокировкой полученный результат не отличается от заданного значения (рис. 2), что свидетельствует об эффективности применяемых методов.
Рис. 2. Выполнение программы с применением блокировки
Предлагаемая разработка предназначена для студентов, изучающих дисциплину «Операционные системы», а также для всех интересующихся использованием критических секций, мьютексов, семафоров и событий при программировании многопоточных приложений.
Библиографическая ссылка
Клименко М.А., Трухан Д.А. Средства синхронизации потоков, критические секции и тупики // Современные наукоемкие технологии. – 2013. – № 8-2. – С. 200-202;URL: https://top-technologies.ru/ru/article/view?id=32079 (дата обращения: 17.08.2024).