Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Работа с семафорами




 

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

 

CSemaphore(LONG lInitialCount=1,LONG lMaxCount=1, LPCTSTR pstrName=NULL, LPSECURITY_ATTRIBUTES lpsaAttributes=NULL);

 

Семафоры имеют счетчик, указывающий количество задач, которым в настоящее время предоставлен доступ к ресурсу. Если значение счетчика равно нулю, то последующий доступ к ресурсу запрещается до тех пор, пока одна из задач не освободит семафор. Начальное значение счетчика семафора указывается в первом параметре конструктора. Обычно начальное значение задается равным единице, чтобы хотя бы один поток мог получить семафор. Допустимое число потоков, которым будет разрешен одновременный доступ, указывается во втором параметре. Если это значение равно единице, то семафор будет исключающим.

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

Модифицируйте приложение Example, добавив в него функции, использующие семафор. Для этого добавьте в меню Thread пункт Semaphore. Функция OnSemaphore(), реализующая этот пункт, создает три потока, которые используют один и тот же ресурс. Одновременно доступ к ресурсу могут получить только два потока. Третий должен ждать, когда ресурс освободится.

Создавая семафор, вы передаете ему начальное и максимальное значения счетчика, как показано ниже:

 

CSemaphore Semaphore(2, 2);

 

Поскольку в этом примере семафоры будут использоваться для создания потокового класса, логично будет объявить указатель на объект класса CSemaphore в качестве переменной – члена потокового класса, а затем динамически создать объект класса CSemaphore в конструкторе потокового класса, как показано ниже:

 

semaphore = new CSemaphore(2, 2);

 

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

CSingleLock singleLock(semaphore);

 

Затем для уменьшения значения счетчика семафора вызывается метод Lock() класса CSingleLock:

 

singleLock.Lock();

 

На данный момент объект семафора выполнил уменьшение значения своего внутреннего счетчика. Это новое значение сохраняется до тех пор, пока объект семафора не будет освобожден посредством вызова его метода Unlock():

singleLock.Unlock();

 

Если сразу после освобождения семафора происходит выход объекта класса CSingleLock из области видимости (завершение функции, в которой он объявлен), метод Unlock() для объекта singleLock можно не вызывать. Деструктор объекта singleLock, вызванный при завершении работы функции, выполнит Unlock() автоматически.

Доступ к разделяемому ресурсу осуществим в классе CSomeResource. Класс имеет единственную переменную-член, являющуюся указателем на объект класса CSemaphore. Кроме того, в классе определены конструктор и деструктор, а также метод UseResource(), в котором непосредственно используется семафор.

Файл заголовка SomeResourcе.h:

 

#include "afxmt.h"class CSomeResource{private: CSemaphore* semaphore; public: CSomeResource(); ~CSomeResource(); void UseResource();};

 

Файл реализации класса SomeResourcе.cpp:

 

#include "stdafx.h"#include "SomeResource.h"CSomeResource::CSomeResource(){ semaphore = new CSemaphore(2,2);} CSomeResource::~CSomeResource(){ delete semaphore; } void CSomeResource::UseResource(){ CSingleLock singleLock(semaphore); singleLock.Lock(); Sleep(5000);}

 

В тексте файла, реализующего класс CSomeResource, можно видеть, что объект класса CSemaphore динамически создается в конструкторе класса CSomeResource и уничтожается в его деструкторе. Метод UseResource() эмулирует доступ к ресурсу. Он захватывает семафор, затем ожидает пять секунд и вновь его освобождает.

Модифицируйте приложение Example следующим образом.

1. Добавьте в меню Thread пункт Semaphore и функцию OnSemaphore() в класс CExampleView.

2. Добавьте в проект два новых пустых файла SomeResource.h и SomeResourcе.срр, пользуясь меню File->New. Выберите вкладку Files, типы файлов C/C++ Header File и C++ Source File.

3. Добавьте в эти пустые файлы тексты программ, приведенные выше.

4. Добавьте в файл ExampleView.cpp после директивы

 

#include "ExampleView.h"

 

директиву

 

#include "SomeResource.h"

5. Включите в начало файла, сразу же после директивы #endif, строку

 

CSomeResource someResource;

 

6. Добавьте в файл ExampleView.cpp перед функцией CExampleView::OnSemaphore() три следующие функции:

 

UINT ThreadProc1(LPVOID pParam)

{

someResource.UseResource();

AfxMessageBox("Thread1 had access.");

return 0;

}

UINT ThreadProc2(LPVOID pParam)

{

someResource.UseResource();

AfxMessageBox("Thread2 had access.");

return 0;

}

UINT ThreadProc3(LPVOID pParam)

{

someResource.UseResource();

AfxMessageBox("Thread3 had access.");

return 0;

}

7. Добавьте в функцию CExampleView::OnSemaphore() следующие строки:

AfxBeginThread(ThreadProc1, this);

AfxBeginThread(ThreadProc2, this);

AfxBeginThread(ThreadProc3, this);

 

Теперь откомпилируйте новую версию приложения Example и запустите ее на выполнение. В раскрывшемся главном окне приложения выберите команду Threads->Semaphore. Приблизительно через пять секунд появятся два окна сообщений, информирующие о том, что первый и второй потоки получили доступ к защищенному ресурсу. Еще через пять секунд появится третье окно сообщений, в котором говорится о том, что третий поток также получил доступ к ресурсу. Третьему потоку потребовалось на пять секунд больше по той причине, что первые два потока первыми захватили контроль над ресурсом. Семафор в этой программе организован таким образом, что разрешает доступ к ресурсу только двум потокам одновременно. Таким образом, третий поток вынужден был ожидать, пока первый или второй поток освободит защищенный ресурс.

 




Поделиться с друзьями:


Дата добавления: 2014-11-29; Просмотров: 717; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.007 сек.