
- •Лабораторный практикум «Основы разработки приложений Windows» Книга 2
- •Часть 1. Теоретические сведения4
- •Часть 2. Лабораторный практикум73
- •Часть 1 Теоретические сведения
- •1. Основы архитектурЫ защищенного режима Регистры процессора
- •Адресация памяти
- •2. Логические шрифты Создание логических шрифтов
- •Вывод на экран текстовых строк
- •3. Таймеры Windows Организация и обслуживание таймеров
- •Мультимедийные таймеры
- •Измерение интервалов времени
- •Организация периодического процесса
- •Задание однократного интервала времени
- •4. Дочерние окна Создание и использование дочерних окон
- •Окна предопределенных классов в главном окне
- •5. Вывод растровых изображений
- •Процедура вывода растрового изображения
- •Компоновка составных изображений
- •6. Обслуживание файлов в 32-разрядных приложениях Windows
- •Базовые операции с файлами Открытие и создание файла
- •Запись и чтение файла
- •Файлы, проецируемые в память
- •7. Процессы и потоки
- •Создание дочернего процесса
- •Создание дочернего потока
- •Синхронизация потоков Общие характеристики объектов Windows
- •Синхронизация с помощью состояний потока
- •Синхронизация с помощью событий
- •Критические секции и защита данных
- •8. Библиотеки динамической компоновки
- •Часть 2 Лабораторный практикум Работы лабораторного практикума Работа 1. Создание логических шрифтов
- •Работа 2. Таймеры Windows(индивидуальное задание а)
- •Работа 3. Дочернее окно в главном окне приложения
- •Работа 4. Вывод растровых изображений с использованием совместимой памяти
- •Работа 5. Измерение временных характеристик программы с помощью мультимедийного таймера
- •Работа 6. Вывод движущихся изображений с синхронизацией от системного таймера (индивидуальное задание b)
- •Работа 7. Повышение качества движущихся изображений с помощью совместимой памяти
- •Работа 8. Движение изображения по фоновому рисунку
- •Работа 9. Работа с файлами (индивидуальное задание c)
- •Работа 10. Стандартные диалоги Windows для работы с файлами
- •Работа 11. Проецирование файла в память
- •Работа 12. Потоки (индивидуальное задание d)
- •Работа 13. Синхронизация потоков с помощью событий
- •Работа 14. Защита данных с помощью критической секции
- •Работа 15. Библиотеки динамической компоновки
- •Работа 16. Передача параметров в функции dll-библиотек
- •Индивидуальные задания лабораторного практикума
- •Задание c2.Массив записываемых в файл данных должен представлять собой последовательный ряд из 2000 целых четных чисел.
- •Лабораторный практикум «Основы разработки приложений Windows» Книга 2
Работа 14. Защита данных с помощью критической секции
Составьте программу, наглядно иллюстрирующую использование критических секций для защиты данных общего пользования. Пусть такими данными является банковский счет, с которого два потока будут периодически и параллельно снимать суммы, равные одной денежной единице. Программа будет состоять из функции WinMain(), реализующей первичный поток приложения, а также двух вторичных потоков, имитирующих действия клиентов банка. Результаты работы программы достаточно выводить в окно сообщения, поэтому можно обойтись без главного окна.
Состав глобальных переменных:
структурная переменная CritSectтипаCRITICAL_SECTION;
целочисленная переменная nBalanceдля остатка денег на счете;
булева переменная bGo, управляющая выполнением потоков;
две целочисленные переменные nDeals1иnDeals2для отсчета числа выполненных банковских операций (транзакций) первым и вторым потоками;
два дескриптора создаваемых в программе файлов;
переменная типа DWORD, требуемая для операций записи в файл.
Локальные переменные в главной функции WinMain():
массив из двух переменных hThreads[2]типаHANDLEдля хранения дескрипторов создаваемых потоков;
две переменные типа DWORDдля хранения идентификаторов создаваемых потоков;
символьный массив достаточной длины для формирования итогового сообщения.
Состав главной функции WinMain():
инициализация критической секции вызовом функции InitializeCriticalSection();
создание двух файлов с произвольными именами для записи в них информации о произведенных транзакциях;
создание двух вторичных потоков с рабочими функциями Thread1иThread2;
установка переменной bGo, разрешающей выполнение обоим потокам;
“пустой” цикл while(nBalance>=1), останавливающий выполнение первичного потока (функцииWinMain()) до полного истощения денег на счете;
после выхода из цикла while()сброс переменнойbGo;
ожидание завершения обоих потоков с помощью функции WaitForMultipleObjects();
формирование в символьном массиве (с помощью функции wsprintf()) итогового сообщения, включающего исходную сумму счета, количество транзакций первого и второго потоков, остаток денег на счете, а также сумму, снятую со счета обоими потоками вместе;
вывод сформированной символьной строки в окно сообщения и завершение программы;
закрытие обоих потоков и удаление критической секции.
Рабочие функции потоков ничем не отличаются друг от друга за исключением того, что первый поток, выполнив транзакцию, инкрементирует переменную nDeals1, а второй – переменнуюnDeals2.
Состав рабочих функций потоков:
цикл while(bGo), в который включается весь текст рабочей функции (за исключением последнего предложенияreturn 0);
вход в критическую секцию (функция EnterCriticalSection());
чтение в локальную переменную потока nLocalBalanceтекущего содержимого глобальной переменнойnBalance(суммы денег на счете);
проверка с помощью предложения if(nLocalBalance >=1)наличия денег на счете (все дальнейшие операции выполняются в блокеif, т. е. лишь при положительном результате этого сравнения);
уменьшение значения переменной nLocalBalance на единицу (снятие со счета);
инкремент переменной nDealsилиnDeals2;
формирование символьной строки с текущей суммой на счете (значение переменной nLocalBalance);
запись этой строки в файл, соответствующий данному потоку (эта операция введена для увеличения времени работы функции потока и повышения вероятности ее прерывания с передачей управления другому потоку);
в качестве последней операции перенос значения переменной nLocalBalanceв глобальную переменнуюnBalance;
после закрытия блока ifвыход из критической секции вызовом функцииLeaveCriticalSection()
после закрытия блока whileзавершающий операторreturn 0и закрытие рабочей функции потока.
Программу необходимо сначала отладить при выключенных операциях с критической секцией. Возможный результат работы программы показан на приведенном ниже рисунке:
Видно, что при начальной сумме 100000 единиц со счета было снято в общей сложности 189580 единиц, причем на счете еще осталась некоторая сумма.
После того, как программа будет отлажена, ее следует запустить при включенных операциях с критической секцией. В этом случае сумма сделок должна в точности соответствовать сумме вклада, а остаток вклада должен быть равен 0.