Параллельное программирование на С++ в действии. Практика разработки многопоточных программ | страница 32
Поддержка операции перемещения в классе >std::thread
означает, что владение можно легко передать при возврате из функции, как показано в листинге 2.5.
Листинг 2.5. Возврат объекта >std::thread
из функции
>std::thread f() {
> void some_function();
> return std::thread(some_function);
>}
>std::thread g() {
> void some_other_function(int);
> std::thread t(some_other_function, 42);
> return t;
>}
Аналогично, если требуется передать владение внутрь функции, то достаточно, чтобы она принимала экземпляр >std::thread
по значению в качестве одного из параметров, например:
>void f(std::thread t);
>void g() {
> void some_function();
> f(std::thread(some_function));
> std::thread t(some_function);
> f(std::move(t));
>}
Одно из преимуществ, которые даёт поддержка перемещения в классе >std::thread
, заключается в том, что мы можем модифицировать класс >thread_guard
из листинга 2.3, так чтобы он принимал владение потоком. Это позволит избежать неприятностей в случае, когда время жизни объекта >thread_guard
оказывает больше, чем время жизни потока, на который он ссылается, а, кроме того, это означает, что никто другой не сможет присоединиться к потоку или отсоединить его, так как владение было передано объекту >thread_guard
. Поскольку основное назначение этого класса гарантировать завершение потока до выхода из области видимости, я назвал его >scoped_thread
. Реализация и простой пример использования приведены в листинге 2.6.
Листинг 2.6. Класс >scoped_thread
и пример его использования
>class scoped_thread {
> std::thread t;
>public:
> explicit scoped_thread(std::thread t_) : ←
(1)
> t(std::move(t_)) {
> if (!t.joinable()) ←
(2)
> throw std::logic_error("No thread");
> }
> ~scoped_thread() {
> t.join(); ←
(3)
> }
> scoped_thread(scoped_thread const&)=delete;
> scoped_thread& operator=(scoped_thread const&)=delete;
>};
>struct func; ←
см. листинг 2.1
>void f() {
> int some_local_state;
> scoped_thread t(std::thread(func(some_local_state))); ←
(4)
> do_something_in_current_thread();
>} ←
(5)
Этот пример очень похож на приведенный в листинге 2.3, только новый поток теперь передается непосредственно конструктору >scoped_thread
(4), вместо того чтобы создавать для него отдельную именованную переменную. Когда новый поток достигает конца >f
(5), объект >scoped_thread
уничтожается, а затем поток соединяется (3) с потоком, переданным конструктору (1). Если в классе >thread_guard
из листинга 2.3 деструктор должен был проверить, верно ли, что поток все еще допускает соединение, то теперь мы можем сделать это в конструкторе