Кроме того, вы можете добавить поток в группу, не создавая его непосредственно, а используя для этого вызов функции 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
#include
#include
// Простой класс очереди; в реальной программе вместо него следует
// использовать std::queue
template
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 list_;
boost::mutex mutex_;
};
Queue 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) , который обеспечивает монопольный доступ к чему-либо.
Остальная часть обсуждения в целом посвящена мьютексам, и в частности методам использования boost::mutexдля сериализации доступа к ресурсам. Я использую терминологию подхода «концепция/модель», о котором я говорил кратко во введении настоящей главы. Концепция — это абстрактное (независимое от языка) описание чего-либо, а модель концепции — конкретное ее представление в форме класса С++. Уточнение концепции — это определенная концепция с некоторыми дополнительными возможностями.
Читать дальше