Информационный сайт

 

Реклама
bulletinsite.net -> Книги на сайте -> Программисту -> Янг Майкл Дж. -> "Visual С++ 6. Полное руководство: В 2 т.(том2)" -> 117

Visual С++ 6. Полное руководство: В 2 т.(том2) - Янг Майкл Дж.

Янг Майкл Дж. Visual С++ 6. Полное руководство: В 2 т.(том2) — Бином, 2006. — 530 c.
Скачать (прямая ссылка): vicualcc2006t2.djvu
Предыдущая << 1 .. 111 112 113 114 115 116 < 117 > 118 119 120 121 122 123 .. 173 >> Следующая

Чтобы предотвратить подобную ошибку, нужно синхронизировать действия отдельных потоков. Существует много других ситуаций, в которых может понадобиться синхронизация потоков. Во-первых, существуют ресурсы, не допускающие одновременного доступа несколькими потоками, например, объекты MFC-классов (как упоминалось ранее), графические объекты, не предназначенные для совместного использования файлы и аппаратные средства. Кроме того, может потребоваться синхронизировать действия потока-производителя и потока-потребителя. Например, если один поток записывает символы в буфер, другой читает и удаляет символы из буфера, то читающему потоку требуется подождать, пока записывающий поток добавит символ, а записывающему потоку подождать, пока читающий поток удалит символ.
Для этих целей Win32 API содержит набор объектов синхронизации, использующихся для синхронизации отдельных потоков (в этом контексте термин объект ссылается не на объект С++). Используя эти объекты, можно организовать синхронизацию потоков: запрет одновременного доступа к ресурсам более одного потока, ограничение количества потоков, одновременно получающих доступ к ресурсам, или организацию сигнализации между потоками.
Примечание
MFC-классы предоставляют набор классов для объектов синхронизации управления, которые используются вместо вызова функций Win32 API, рассмотренных в этой и следующей главах. Свойства этих классов менее понятны, чем функции Win32 API, и они не допускают использования некоторых приемов программирования, например, ожидания прерывания потока или процесса. В MFC существуют такие классы синхронизации: CSyncObject, CSemaphore, CCri tical Section, CMutex, CEvent, CSingleLock, CMultiLock. Использование этих классов описано в следующих разделах справочной системы: Visual С++ Documentation, Using Visual С++, Visual С++ Programmer's Guide, Adding Program Functionality, Detail, Multithreading Topic, Multithreading with С++ and MFC, Multithreading: How to Use the Synchronization Classes.
Одним из наиболее простых и типичных объектов синхронизации является мьютекс. Его название происходит от английского выражения mutual exclusion (взаимное исключение). Этот объект используется для ограничения одновременного доступа к данному ресурсу единственным потоком.
При использовании мыотекса вызывается функция ::CreateMutex Win32 API для создания объекта синхронизации — мьютекса. Это можно сделать в любом потоке программы. Например:
HANDLE HMutex; // объявляется глобально, и все потоки // имеют к нему доступ
//...
void SomeFunction () <
//. . .
HMutex = ::CreateMutex
(NULL, // присваивает стандартные атрибуты защиты // (ненаследуемый дескриптор)
FALSE, // мыотекс изначально свободный
NULL); // имя мьютексу не присваивается //. . . }
Первый параметр задает атрибуты защиты мьютекса. При передаче значения NULL ему присваиваются стандартные значения атрибутов, а дескриптор мьютекса устанавливается ненаследуемым (наследование дескриптора рассмотрено в гл. 23). Во втором параметре описывается начальное состояние мьютекса. Передача значения true создает изначально свободный мьютекс (при передаче значения false мьютекс изначально будет занят; эти состояния рассмотрены далее). Третий параметр задает имя мьютекса. Значение NULL создает мьютекс без имени. Задание имени позволяет получать доступ к мьютексу из другого процесса (гл. 23). Функция : ; CreateMutex возвращает дескриптор, используемый потоками программы для ссылки на мьютекс.
Далее следует добавить вызов функции : :WaitForSingleObject Win32 API в начало каждого блока, обращающегося к защищаемым ресурсам, и вызов функции Win32 API : :ReleaseMutex в конец каждого из этих блоков. Например, можно запретить одновременный доступ нескольких потоков к глобальному счетчику таким образом.
: :WaitForSingleObject
(HMutex, // дескриптор мьютекса
INFINITE); // ждите столько, сколько нужно
++Count;
cout « Count « '\n';
::ReleaseMutex (HMutex);
При вызове последней функции происходит следующее. Мьютекс, как и любой другой объект синхронизации, находится в одном из двух состояний: свободном (signaled) или занятом (nonsignaled). Как правило, вновь созданный мьютекс свободен. Если при вызове потоком функции : : WaitForSingleObj ect мьютекс свободен, то функция переводит мьютекс в занятое состояние и сразу же возвращается обратно. Поток продолжает выполнять защищенный блок, после чего вызывает функцию : .-ReleaseMutex и устанавливает мьютекс снова в свободное состояние. Если мьютекс занят при вызове функции : : WaitForSingleObj ect (другой поток в это время выполняется в защищенном блоке), то эта функция сначала ждет, когда мьютекс станет свободным, а затем устанавливает мьютекс в занятое состояние и возвращается. В результате только один поток может выполнять защищенный блок кода в один момент времени. Когда объект синхронизации занят, считается, что он принадлежит потоку, который перевел его в занятое состояние.
Например, если несколько блоков используют счетчик Count, нужно окружить каждый блок вызовами функций ::WaitForSingleObject и ::ReleaseMutex, задавая один и тот же мьютекс в каждом вызове. В этом случае, если один поток выполняет любой блок кода, то другой — не может выполнить ни один из этих блоков.
Предыдущая << 1 .. 111 112 113 114 115 116 < 117 > 118 119 120 121 122 123 .. 173 >> Следующая
Реклама
Авторские права © 2009 AdsNet. Все права защищены.
Rambler's Top100