Если требуется создать несколько потоков, рассмотрите возможность их группирования в объект 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.

<p>12.2. Обеспечение потокозащищенности ресурсов</p>Проблема

В программе используется несколько потоков и требуется гарантировать невозможность модификации ресурса несколькими потоками одновременно. В целом это называется обеспечением потокозащищенности (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;

Перейти на страницу:

Похожие книги