[英]Running C++ threads from different scope using join()
讓我們假設我們有兩個功能:
void foo1 () {
while (true) {
std::cout << "foo1" << std::endl;
std::this_thread::sleep_for (std::chrono::milliseconds {100});
}
}
void foo2 () {
while (true) {
std::cout << "foo2" << std::endl;
std::this_thread::sleep_for (std::chrono::milliseconds {100});
}
}
我想在不同的線程中啟動它們,但是它們是否啟動取決於某些條件,因此例如執行它們的方式如下:
bool c1 {true};
bool c2 {true};
if (c1) {
std::thread th1 {&foo1};
th1.join ();
}
if (c2) {
std::thread th2 {&foo2};
th2.join ();
}
我知道在這種情況下,只會調用foo1()
而不會調用foo2()
。
我的第一個想法是像這樣使用unique_ptr
:
bool c1 {false};
bool c2 {false};
std::unique_ptr<std::thread> pth1 {};
std::unique_ptr<std::thread> pth2 {};
if (c1) {
pth1 = std::unique_ptr<std::thread> {new std::thread {&foo1}};
}
if (c2) {
pth2 = std::unique_ptr<std::thread> {new std::thread {&foo2}};
}
if (pth1) {
pth1->join ();
}
if (pth2) {
pth2->join ();
}
我的第二個想法是稍微更改設計以始終運行線程,但是如果條件為假,請退出函數,因此請看下面的代碼:
void foo1 (bool c) {
if (c) {
while (true) {
std::cout << "foo1" << std::endl;
std::this_thread::sleep_for (std::chrono::milliseconds {100});
}
}
}
void foo2 (bool c) {
if (c) {
while (true) {
std::cout << "foo2" << std::endl;
std::this_thread::sleep_for (std::chrono::milliseconds {100});
}
}
}
bool c1 {true};
bool c2 {true};
std::thread th1 {&foo1, c1};
std::thread th2 {&foo2, c2};
th1.join ();
th2.join ();
我知道問哪個更好並不總是一個好問題,但是當至少兩個線程從不同作用域開始並且必須將所有它們都加入時,您能否建議我一個好的(也許比提出的解決方案更好)的解決方案?
一個std::thread
對象不必代表一個線程。 我認為最簡單的是:
std::thread th1, th2;
if (c1)
th1 = std::thread{&foo1};
if (c2)
th2 = std::thread{&foo2};
if (th1.joinable())
th1.join();
if (th2.joinable())
th2.join();
甚至:
std::thread maybe_start( void(*f)(), bool c)
{
if (c)
return std::thread{f};
else
return {}
}
void maybe_wait(std::thread& thr)
{
if (thr.joinable())
thr.join();
}
....
std::thread thr1 = maybe_start(&foo1, c1);
std::thread thr2 = maybe_start(&foo2, c2);
maybe_wait(thr1);
maybe_wait(thr2);
您需要諸如線程池之類的東西。 我寫了這個例子來演示想法:
#ifndef DUMMYTHREADPOOL_H_
#define DUMMYTHREADPOOL_H_
#include <thread>
class dummy_thread_pool {
private:
std::vector<std::thread> tp;
dummy_thread_pool(const dummy_thread_pool&){}
public:
dummy_thread_pool(){}
dummy_thread_pool(size_t n)
{
tp.reserve(n);
}
~dummy_thread_pool()
{
tp.clear();
}
void do_join(std::thread& t)
{
t.join();
}
void join_all() {
std::for_each(tp.begin(), tp.end(), std::bind(&dummy_thread_pool::do_join, this, std::placeholders::_1));
}
void wait_for_all()
{
std::thread t(&dummy_thread_pool::join_all, this);
t.join();
}
void add_thread(std::thread t)
{
tp.push_back(std::move(t));
}
};
#endif /* DUMMYTHREADPOOL_H_ */
您的代碼可能如下所示:
bool c1 {true};
bool c2 {true};
dummy_thread_pool dtp;
if (c1) {
std::thread th1 {&foo1};
dtp.add_thread(std::move(th1));
}
if (c2) {
std::thread th2 {&foo2};
dtp.add_thread(std::move(th2));
}
dtp.wait_for_all();
同樣在您的情況下, std::future
和std::async
比std::thread
有用。
您也可以使用boost::thread_group
:
boost::thread_group tg;
tg.create_thread(/*your thread*/);
tg.join_all();
您的第二個解決方案是非常好的。 但是我們一定不要忘記調用join
方法。 為了簡化,您可以通過以下方式使用RAII:
class thread_guard
{
std::thread thread_;
public:
explicit thread_guard( std::thread thread )
thread_{ std::move( thread ) }
{
if ( !thread.joinable( ) ) {
throw std::logic_error( "No joinable thread!" );
}
}
~thread_guard( ) {
thread_.join( );
}
thread_guard( const thread_guard& ) = delete;
thread_guard & operator=( const thread_guard& ) = delete;
};
void f( ) {
thread_guard thread1( std::thread(&foo1, c1) );
}
您也可以將thread poll與thread_guard
一起使用,但是在這種情況下,線程數量很少,這會更復雜
或者可以通過以下非常簡單的方式進行操作:
std::vector<std::thread> threads;
//add threads in vector
std::for_each(threads.begin(),threads.end(),
std::mem_fn(&std::thread::join));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.