- •Визуальные средства разработки приложений
- •Содержание
- •Лабораторная работа № 1 Использование технологии ole db
- •1.1.Наиболее важные технологии сом
- •1.2. Единообразная передача данных и объекты с подключением
- •1.Методические указания
- •Лабораторная работа №2 Построение приложения с использованием компонентов ActiveX
- •2.1. Управляющие элементы ActiveX
- •2.2. Методические указания
- •Лабораторная работа №3 Использование потоков в приложении
- •3.1.Потоковая многозадачность
- •3.2.Потоки mfc
- •3.3. Синхронизация потоков
- •3.4. Методические указания
- •3.4.1. Создание рабочего потока
- •3.4.2.Остановка и возобновление выполнения потоков
- •3.4.3. Управление приоритетами потоков
- •3.4.4.Синхронизация потоков
- •3.4.5.Работа с семафорами
- •3.4.6.Работа с объектами событий
- •3.4.7 Использование критической секции
- •3.4.8 Использование исключающего семафора
- •Варианты индивидуального задания
- •Лабораторная работа №4 Программирование для Интернета с использованием Windows Sockets
- •4.1. Сокеты, порты, адреса
- •4.2. Модель клиент - сервер
- •Связь клиент - сервер
- •4.3. Класс cAsyncSocket
- •4.4. Создание сетевого приложения
- •4.4.1. Создание каркаса приложения
- •4.4.2.Функции класса cAsyncSocket Class
- •Задание к лабораторной работе
- •Варианты индивидуального задания
- •Литература
- •220027, Минск, ул. П. Бровки, 6
3.4.6.Работа с объектами событий
Объект события используется для оповещения процесса или потока о том, что произошло некоторое событие. Для работы с такими объектами предназначен класс CEvent. Конструктор класса имеет следующий прототип:
CEvent( BOOL bInitiallyOwn = FALSE, BOOL bManualReset = FALSE,
LPCTSTR lpszName = NULL,
LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );
Значение первого параметра определяет начальное состояние объекта. Если оно равно TRUE, то объект события установлен (событие произошло), а если FALSE, то объект не установлен или сброшен (событие не произошло).
Второй параметр указывает, каким образом состояние объекта будет изменяться при выполнении события. Если значение параметра равно TRUE (не ноль), то объект может быть сброшен только путем вызова метода ResetEvent класса CEvent. В противном случае объект автоматически сбрасывается после предоставления блокированному потоку доступа к ресурсу.
Третий параметр конструктора указывает на строку, содержащую имя объекта события. Поименованные объекты события становятся системными объектами и могут использоваться другими процессами. Вместо имени строки можно указать NULL - в этом случае объект события будет локализован внутри одного процесса.
Последний параметр конструктора является указателем на набор атрибутов прав доступа, связанный с объектом события. Если этот параметр равен NULL, то объект события наследует данный набор у вызвавшего его потока.
Когда объект события создан, то поток, ожидающий данное событие, должен создать объект класса CSingleLock, для которого затем следует вызвать метод Lock. При этом выполнение данного потока останавливается до тех пор, пока не произойдет ожидаемое событие. Для сигнализации о том, что событие произошло, предназначена функция SetEvent класса CEvent. Она переводит объект события в состояние «сигнализирует». При этом поток, ожидающий событие, выйдет из остановленного состояния (вызванный им метод Lock завершится) и выполнение потока продолжится.
Чтобы продемонстрировать работу с объектами события, дополним наше приложение следующими функциями. Создадим два пункта меню: «Start Thread 2» и «End Thread 2». По пункту «Start Thread 2» должен запускаться процесс MyThread2, по пункту «End Thread 2» должен заканчиваться процесс MyThread2 с выдачей сообщения "MyThread2 ended". Если запуск процесса легко осуществить с помощью объекта события, то завершение процесса легче реализовать с помощью глобальной переменной.
Всем потокам процесса доступны все глобальные переменные процесса. Но может возникнуть ситуация, когда выполнение потока прерывается в тот момент, когда значение глобальной переменной является некорректным. Значение переменной может загружаться в регистр для выполнения некоторых операций. Если прерывание наступит в момент, когда значение переменной находится в регистре, а второй поток изменит ее значение в памяти, первый поток испортит ее значение, возвращая из регистра соответствующее значение. Одним из способов решения такой проблемы является объявление переменной как volatile, что гарантирует, что она не будет размещаться компилятором в регистре.
Выполните следующие действия для реализации объекта события и использования глобальной переменной.
1. С помощью редактора ресурсов добавьте команды Start Thread 2 и End Thread 2 в меню Thread приложения. Присвойте этим командам идентификаторы ID_STARTTHREAD2 и ID_ENDTHREAD2.
2. С помощью СlassWizard свяжите команду ID_STARTTHREAD2 с функцией обработки сообщения OnStartthread2(), команду ID_ENDTHREAD2 с функцией обработки сообщения OnEndhread2(). Перед тем как добавить новую функцию, убедитесь, что в поле Class Name выбрано значение CExampleView.
3. Добавьте в начало файла ExampleView.cpp приведенную ниже строку, поместив ее сразу после строки #include "SomeResource.h":
#include "afxmt.h"
Этот оператор подключает заголовочный файл для работы с классами объектов синхронизации.
4. Включите в начало файла ExampleView.cpp, сразу же после объявления
CSomeResource someResource
следующую строку:
volatile bool keeprunning;
5. Добавьте в начало файла ExampleView.cpp приведенные ниже строки, поместив их после строки volatile bool keeprunning;:
CEvent threadStart;
CEvent threadEnd;
6. Добавьте в функцию UINT MyThread2(LPVOID pParam) в файле ExampleView.cpp строки
CSingleLock syncObjStart(&threadStart);
syncObjStart.Lock();
перед циклом for. Первая функция создает объект syncObjStart класса CSingleLock для объекта события threadStart. Это вызов конструктора.
Вторая функция вызывает метод Lock() для этого объекта. Выполнение данного потока останавливается до тех пор, пока не произойдет событие для этого объекта.
7. Добавьте в функцию UINT MyThread2(LPVOID pParam) в файле ExampleView.cpp в теле цикла после строки
MessageBeep(0);
строки
if (keeprunning==FALSE){
AfxMessageBox("MyThread2 ended");
break;}
Теперь при каждом проходе цикла будет осуществляться проверка глобальной переменной, и если она станет равна FALSE, цикл прервется и поток завершит свою работу.
8. Добавьте в функцию void CExampleView::OnStartthread2() строки:
keeprunning=TRUE;//начальное значение переменной keeprunning
threadStart.SetEvent();//объект события в состояние «сигнализирует» (событие произошло).
После ее выполнения метод Lock(), который ждет этого события, завершает свою работу, и выполняются следующие функции.
9. Добавьте в функцию void CExampleView::OnEndthread2() строку:
keeprunning=FALSE;
Теперь очередной цикл в функции MyThread2 прервется, и поток завершит свою работу.
