使用join()运行来自不同范围的C ++线程

时间:2016-01-21 08:58:10

标签: c++ multithreading c++11

让我们假设我们有两个函数:

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 ();

我知道问哪一个更好并不总是好问题,但是当你至少有两个线程从不同的范围开始并且所有的线程都有不同时,你能否建议我处理好(也许可能比那些更好)解决方案加入?

3 个答案:

答案 0 :(得分:4)

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);

答案 1 :(得分:0)

你需要一些像线程池这样的东西。我写了这个例子来证明这个想法:

#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::futurestd::async代替std::thread可能很有用。

您也可以使用boost::thread_group

boost::thread_group tg;
tg.create_thread(/*your thread*/);
tg.join_all();

答案 2 :(得分:0)

你的第二个解决方案非常好。但我们必须不要忘记调用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_guard一起使用的线程轮询,但在这种情况下使用少量线程会更复杂

或者可以这么简单地做到这一点:

std::vector<std::thread> threads;
//add threads in vector
std::for_each(threads.begin(),threads.end(),
    std::mem_fn(&std::thread::join));