Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторный практикум «Основы разработки приложений Windows» книга 2.DOC
Скачиваний:
91
Добавлен:
10.05.2014
Размер:
827.9 Кб
Скачать

Критические секции и защита данных

Критической секцией называется произвольный фрагмент программы, который должен обладать монопольным доступом к некоторым данным любого содержания и объема. Критические секции можно использовать только для синхронизации потоков, входящих в единый процесс; если требуется обеспечить поочередный доступ к общим данным потоков, входящих в разные процессы, то в этом случае надо вместо критических секций использовать другие объекты Windows – мьютексы.

Для использования в программе критических секций следует прежде всего объявить среди глобальных данных структурную переменную типа CRITICAL_SECTION:

CRITICAL_SECTION CritSect;

Переменная CritSectвнешне никак не связана ни с защищаемыми данными, ни с тем фрагментом программы, который к этим данным обращается; она, можно сказать, носит организационный характер: с ее помощью Windows определяет, можно ли в данный момент предоставить доступ к общим данным тому или иному потоку.

В первичном потоке программы, еще до создания дочерних потоков, следует выполнить инициализацию объекта Windows “критическая секция”. Эта инициализация выполняется вызовом функции InitializeCriticalSection()с указанием в качестве ее параметра адреса созданной ранее глобальной структурной переменной типаCRITICAL_SECTION.

Фрагменты потоков, в которых осуществляется обращение к общим данным и которые, собственно, и называются критическими секциями, защищаются функциональными скобками

EnterCriticalSection(&CritSect)

...

LeaveCriticalSection(&CritSect)

с указанием в качестве параметра адреса той же структурной переменной типа CRITICAL_SECTION.

Какие изменения в ход выполнения потоков вносит такая организация? Обычно каждому потоку система по очереди выделяет кванты времени, в течение которых потоки и выполняются. "Отнять" время процессора у потока система может в любой момент, на любой его команде. При наличии в потоке критической секции алгоритм квантования времени усложняется. Если первый поток вошел в свою критическую секцию, система по-прежнему может в какой-то момент времени приостановить его выполнение и передать время процессора другому потоку, в том числе и второму потоку, связанному с той же переменной типа CRITICAL_SECTION. Однако как только второй поток подойдет к своей критической секции и вызовет функциюEnterCriticalSection(), система прервет его выполнение и отдаст время процессора либо снова первому потоку, либо другим потокам, действующим в системе. Пока первый поток не выйдет изсвоейкритической секции (вызовом функцииLeaveCriticalSection()), второй поток войти всвоюкритическую секцию не может. В результате, пока первый поток не закончит работу с общими данными, они будут недоступны второму потоку.

Разумеется, в процессе может существовать любое количество потоков, работающих с общими данными. В любом случае обращаться к общим данным они смогут только поочередно.

В каких случаях надо защищать данные от другого потока? Если общие для нескольких потоков данные только читаются, то к таким данным может обращаться любое число потоков. Проблемы возникают в том случае, если потоки как-то видоизменяют данные – модифицируют отдельные элементы, уничтожают их или добавляют. Пусть общие данные олицетворяют собой счет в банке, доступный нескольким клиентам – мужу и жене, например, или нескольким агентам по закупке некоторой продукции. Клиенты снимают деньги в банке с помощью программы, в которой каждому клиенту отведен отдельный поток. Получив запрос клиента на снятие некоторой суммы, программа проверяет наличие такой суммы на счете, оформляет необходимые документы, выдает клиенту деньги и уменьшает величину счета на снятую сумму.

Представим теперь, что где-либо между действиями по проверке суммы на счете и ее уменьшением система передала управление потоку второго клиента, который тоже поставил запрос на снятие денег со счета. Поскольку на счете пока еще имеется прежняя сумма, второй поток ее проанализирует и, обнаружив, что она достаточно велика, уменьшит в соответствии с запросом второго клиента. После того как управление вернется в первый поток, он продолжит анализ старойсуммы и тоже снимет деньги со счета, хотя их там, возможно, недостаточно или вообще нет.

Защита с помощью критической секции всего блока действий по анализу суммы счета, выдаче денег клиенту и коррекции счета приведет к тому, что запросы всех клиентов на снятие денег будут выполняться по очереди и не смогут прерывать друг друга, чем и будет обеспечен правильный алгоритм анализа остатка средств на счете.

С целью экономии системных ресурсов созданные объекты критических секций следует удалять после того, как отпала необходимость в их использовании. Удаление критической секции осуществляется вызовом предусмотренной для этого функции Windows с указанием адреса соответствующей структурной переменной:

DeleteCriticalSection(CritSect);

Критические секции являются одним из наиболее используемых механизмов защиты данных общего пользования в многопоточных системах. Еще раз укажем, что защищать следует лишь те данные, которые модифицируются потоками; если потоки только читают данные, не изменяя их, то обращение к ним многих потоков осуществляется безболезненно.