- Любовные романы
- Фантастика и фэнтези
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
C++. Сборник рецептов - Д. Стефенс
Шрифт:
Интервал:
Закладка:
После создания потока myThread поток main продолжает свою работу, по крайней мере на мгновение, пока не достигнет следующей строки.
boost::thread::yield();
Это переводит текущий поток (в данном случае поток main) в неактивное состояние, что означает переключение операционной системы на другой поток или процесс, используя некоторую политику, которая зависит от операционной системы. С помощью функции yield операционная система уведомляется о том, что текущий поток хочет уступить оставшуюся часть кванта времени. В это время новый поток выполняет threadFun. После завершения threadFun дочерний поток исчезает. Следует отметить, что объект thread не уничтожается, потому что он является объектом С++, который по-прежнему находится в области видимости. Эта особенность играет важную роль.
Объект потока — это некий объект, существующий в динамической памяти или в стеке и работающий подобно любому другому объекту С++. Когда программный код выходит из области видимости потока, все находящиеся в стеке объекты потока уничтожаются, или, с другой стороны, когда вызывающая программа выполняет оператор delete для thread*, исчезает соответствующий объект thread, который находится в динамической памяти. Но объекты thread выступают просто как прокси относительно реальных потоков операционной системы, и когда они уничтожаются, потоки операционной системы не обязательно исчезают. Они просто отсоединяются, что означает невозможность их подключения в будущем. Это не так уж плохо.
Потоки используют ресурсы, и в любом (хорошо спроектированном) многопоточном приложении управление доступом к таким ресурсам (к объектам, сокетам, файлам, «сырой» памяти и т.д.) осуществляется при помощи мьютексов, которые являются объектами, обеспечивающими последовательный доступ к каким-либо объектам со стороны нескольких потоков (см. рецепт 12.2). Если поток операционной системы оказывается «убитым», он не будет освобождать свои блокировки и свои ресурсы, подобно тому как «убитый» процесс не оставляет шансов на очистку буферов или правильное освобождение ресурсов операционной системы. Простое завершение потока в тот момент, когда вам кажется, что он должен быть завершен, — это все равно что убрать лестницу из-под маляра, когда время его работы закончилось.
Поэтому предусмотрена функция-член join. Как показано в примере 12.1, вы можете вызвать join, чтобы дождаться завершения работы дочернего потока, join — это вежливый способ уведомления потока, что вы собираетесь ждать завершения его работы.
myThread.join();
Поток, вызвавший функцию join, переходит в состояние ожидания, пока не закончит свою работу другой поток, представленный объектом myThread. Если он никогда не завершится, то никогда не завершится и join. Применение join — наилучший способ ожидания завершения работы дочернего потока.
Возможно, вы заметили, что, если передать что-либо осмысленное функции threadFun, но закомментировать join, поток не завершит свою работу. Вы можете убедиться в этом, выполняя в threadFun цикл или какую-нибудь продолжительную операцию. Это объясняется тем, что операционная система уничтожает процесс вместе со всеми его дочерними процессами независимо от того, закончили или нет они свою работу. Без вызова join функция main не будет ждать окончания работы своих дочерних потоков: она завершается, и поток операционной системы уничтожается.
Если требуется создать несколько потоков, рассмотрите возможность их группирования в объект thread_group. Объект thread_group может управлять объектами двумя способами. Во-первых, вы можете вызвать add_thread с указателем на объект thread, и этот объект будет добавлен в группу. Ниже приводится пример.
boost::thread_group grp;
boost::thread* p = new boost::thread(threadFun);
grp.add_thread(p);
// выполнить какие-нибудь действия...
grp.remove_thread(p);
При вызове деструктора grp он удалит оператором delete каждый указатель потока, который был добавлен в add_thread. По этой причине вы можете добавлять в thread_group только указатели объектов потоков, размещённых в динамической памяти. Удаляйте поток путем вызова remove_thread с передачей адреса объекта потока (remove_thread находит в группе соответствующий объект потока, сравнивая значения указателей, а не сами объекты). remove_thread удалит указатель, ссылающийся на этот поток группы, но вам придется все же удалить сам поток с помощью оператора delete.
Кроме того, вы можете добавить поток в группу, не создавая его непосредственно, а используя для этого вызов функции create_thread, которая (подобно объекту потока) принимает функтор в качестве аргумента и начинает его выполнение в новом потоке операционной системы. Например, для порождения двух потоков и добавления их в группу сделайте следующее.
boost::thread_group grp;
grp.create_thread(threadFun);
grp.create_thread(threadFun); // Теперь группа grp содержит два потока
grp.join_all(); // Подождать завершения всех потоков
При добавлении потоков в группу при помощи create_thread или add_thread вы можете вызвать join_all для ожидания завершения работы всех потоков группы. Вызов join_all равносилен вызову join для каждого потока группы: join_all возвращает управление после завершения работы всех потоков группы.
Создание объекта потока позволяет начать выполнение отдельного потока. Однако с помощью средств библиотеки Boost Threads это делается обманчиво легко, поэтому необходимо тщательно обдумывать проект. Прочтите остальные рецепты настоящей главы, где даются дополнительные предостережения относительно применения потоков.
Смотри такжеРецепт 12.2.
12.2. Обеспечение потокозащищенности ресурсов
ПроблемаВ программе используется несколько потоков и требуется гарантировать невозможность модификации ресурса несколькими потоками одновременно. В целом это называется обеспечением потокозащищенности (thread-safe) ресурсов или сериализацией доступа к ним.
РешениеИспользуйте класс mutex, определенный в boost/thread/mutex.hpp, для синхронизации доступа к потокам. Пример 12.2 показывает, как можно использовать в простых случаях объект mutex для управления параллельным доступом к очереди.
Пример 12.2. Создание потокозащищенного класса
#include <iostream>
#include <boost/thread/thread.hpp>
#include <string>
// Простой класс очереди; в реальной программе вместо него следует
// использовать std::queue
template<typename T>
class Queue {
public:
Queue() {}
~Queue() {}
void enqueue(const T& x) {
// Блокировать мьютекс для этой очереди
boost::mutex::scoped_lock lock(mutex_);
list_.push_back(x);
// scoped_lock автоматически уничтожается (и, следовательно, мьютекс
// разблокируется) при выходе из области видимости
}
T dequeue() {
boost::mutex::scoped_lock lock(mutex_);
if (list_.empty())
throw "empty!"; // Это приводит к выходу из текущей области
T tmp = list_.front(); // видимости, поэтому блокировка освобождается
list_.pop_front();
return(tmp);
} // Снова при выходе из области видимости мьютекс разблокируется
private:
std::list<T> list_;
boost::mutex mutex_;
};
Queue<std::string> queueOfStrings;
void sendSomething() {
std::string s;
for (int i = 0; i < 10; ++i) {
queueOfStrings.enqueue("Cyrus");
}
}
void recvSomething() {
std::string s;
for(int i = 0; i < 10; ++i) {
try {
s = queueOfStrings.dequeue();
} catch(...) {}
}
}
int main() {
boost::thread thr1(sendSomething);
boost::thread thr2(recvSomething);
thr1.join();
thr2.join();
}
ОбсуждениеОбеспечение потокозащищенности классов, функций, блоков программного кода и других объектов является сущностью многопоточного программирования. Если вы проектируете какой-нибудь компонент программного обеспечения с возможностями многопоточной обработки, то можете постараться обеспечить каждый поток своим набором ресурсов, например объектами в стеке и динамической памяти, ресурсами операционной системы и т.д. Однако рано или поздно вам придется обеспечить совместное использование различными потоками каких-либо ресурсов. Это может быть совместная очередь поступающих запросов (как это происходит на многопоточном веб-сервере) или нечто достаточно простое, как поток вывода (например, в файл журнала или даже в cout). Стандартный способ координации безопасного совместного использования ресурсов подразумевает применение мьютекса (mutex), который обеспечивает монопольный доступ к чему-либо.