C++. Сборник рецептов
Шрифт:
Объекты
mutex
блокируются и разблокируются, используя несколько различных стратегий блокировки, самой простой из которых является блокировка scoped_lock
. scoped_lock
— это класс, при конструировании объекта которого используется аргумент типа mutex
, блокируемый до тех пор, пока не будет уничтожена блокировка lock
. Рассмотрим функцию-член enqueue
в примере 12.2, которая показывает, как scoped_lock
работает совместно с мьютексом mutex_
. void enqueue(const T& x) {
boost::mutex::scoped_lock lock(mutex_);
list_.push_back(x);
} //
разблокировано!
Когда
lock
уничтожается, mutex_
разблокируется. Если lock
конструируется для объекта mutex
, который уже заблокирован другим потоком, текущий поток переходит в состояние ожидания до тех пор, пока lock
не окажется доступен. Такой подход поначалу может показаться немного странным: а почему бы мьютексу
mutex
не иметь методы lock
и unlock
? Применение класса scoped_lock
, который обеспечивает блокировку при конструировании и разблокировку при уничтожении, на самом деле более удобно и менее подвержено ошибкам. Когда вы создаете блокировку, используя scoped_lock
, мьютекс блокируется на весь период существования объекта scoped_lock
, т.е. вам не надо ничего разблокировать в явной форме на каждой ветви вычислений. С другой стороны, если вам приходится явно разблокировать захваченный мьютекс, необходимо гарантировать перехват любых исключений, которые могут быть выброшены в вашей функции (или где-нибудь выше ее в стеке вызовов), и гарантировать разблокировку mutex
. При использовании scoped_lock
, если выбрасывается исключение или функция возвращает управление, объект scoped_lock
автоматически уничтожается и mutex
разблокируется. Использование мьютекса позволяет сделать всю работу, однако хочется немного большего. При таком подходе нет различия между чтением и записью, что существенно, так как неэффективно заставлять потоки ждать в очереди доступа к ресурсу, когда многие из них выполняют только операции чтения, для которых не требуется монопольный доступ. Для этого в библиотеке Boost Threads предусмотрен класс
read_write_mutex
. Пример 12.3 показывает, как можно реализовать пример 12.2, используя read_write_mutex
с функцией-членом front
, которая позволяет вызывающей программе получить копию первого элемента очереди без его выталкивания. Пример 12.3. Использование мьютекса чтения/записи
#include <iostream>
#include <boost/thread/thread.hpp>
#include <boost/thread/read_write_mutex.hpp>
#include <string>
template<typename T>
class Queue {
public:
Queue : // Использовать мьютекс чтения/записи и придать ему приоритет
// записи
rwMutex_(boost::read_write_scheduling_policy::writer_priority) {}
~Queue {}
void enqueue(const T& x) {
//
Использовать блокировку чтения/записи, поскольку enqueue
// обновляет состояние
boost::read_write_mutex::scoped_write_lock writeLock(rwMutex_);
list_.push_back(x);
}
T dequeue {
// Снова использовать блокировку для записи
boost::read_write_mutex::scoped_write_lock writeLock(rwMutex_);
if (list_.empty)
throw "empty!";
T tmp = list_.front;
list_.pop_front;
return(tmp);
}
T getFront {
// Это операция чтения, поэтому требуется блокировка только для чтения
boost::read_write_mutex::scoped_read_lock.readLock(rwMutex_);
if (list_.empty)
throw "empty!";
return(list_.front);
}
private:
std::list<T> list_;
boost::read_write_mutex rwMutex_;
};
Queue<std::string> queueOfStrings;
void sendSomething {
std::string s;
for (int i = 0, i < 10; ++i) {
queueOfStrings.enqueue("Cyrus");
}
}
void checkTheFront {
std::string s;
for (int i=0; i < 10; ++i) {
try {
s = queueOfStrings.getFront;
} catch(...) {}
}
}
int main {
boost::thread thr1(sendSomething);
boost::thread_group grp;
grp.сreate_thread(checkTheFront);
grp.create_thread(checkTheFront);
grp.сreate_thread(checkTheFront);
grp_create_thread(checkTheFront);
thr1.join;
grp.join_all;
}
Здесь необходимо отметить несколько моментов. Обратите внимание, что теперь я использую
read_write_mutex
. boost::read_write_mutex rwMutex_;
При использовании мьютексов чтения/записи блокировки тоже выполняются иначе. В примере 12.3, когда мне нужно заблокировать
Queue
для записи, я создаю объект класса scoped_write_lock
. boost::read_write_mutex::scoped_write_lock writeLock(rwMutex_);
Поделиться:
Популярные книги
Вонгозеро
1. Вонгозеро
Детективы:
триллеры
9.19
рейтинг книги
Кротовский, может, хватит?
3. РОС: Изнанка Империи
Фантастика:
попаданцы
альтернативная история
аниме
7.50
рейтинг книги
Сборник коротких эротических рассказов
Любовные романы:
эро литература
love action
7.25
рейтинг книги
Архонт
5. Стеллар
Фантастика:
боевая фантастика
рпг
7.80
рейтинг книги
Медиум
1. О чем молчат могилы
Фантастика:
фэнтези
7.90
рейтинг книги
Титан империи 8
8. Титан Империи
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Ведьма Вильхельма
Любовные романы:
любовно-фантастические романы
8.67
рейтинг книги
Волхв
3. Волшебник
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Я еще не барон
1. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Темный Патриарх Светлого Рода
1. Темный Патриарх Светлого Рода
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Пистоль и шпага
2. Штуцер и тесак
Фантастика:
альтернативная история
8.28
рейтинг книги
Корпулентные достоинства, или Знатный переполох. Дилогия
Фантастика:
юмористическая фантастика
7.53
рейтинг книги
Ученик. Книга 4
4. Ученик
Фантастика:
фэнтези
5.67
рейтинг книги
Часовое имя
4. Часодеи
Детские:
детская фантастика
9.56