c++11中关于std::thread的join的思考

c++中关于std::thread的join的思考c++

std::thread是c++11新引入的线程标准库,经过其能够方便的编写与平台无关的多线程程序,虽然对比针对平台来定制化多线程库会使性能达到最大,可是会丧失了可移植性,这样对比其余的高级语言,可谓是一个不足。终于在c++11认可多线程的标准,可谓可喜可贺!!!多线程

在使用std::thread的时候,对建立的线程有两种操做:等待/分离,也就是join/detach操做。join()操做是在std::thread t(func)后“某个”合适的地方调用,其做用是回收对应建立的线程的资源,避免形成资源的泄露。detach()操做是在std::thread t(func)后立刻调用,用于把被建立的线程与作建立动做的线程分离,分离的线程变为后台线程,其后,建立的线程的“死活”就与其作建立动做的线程无关,它的资源会被init进程回收。函数

在这里主要对join作深刻的理解。性能

因为join是等待被建立线程的结束,并回收它的资源。所以,join的调用位置就比较关键。好比,如下的调用位置都是错误的。线程

例子一:c++11

void test()
{
}

bool do_other_things()
{
}

int main()
{
    std::thread t(test);
    int ret = do_other_things();
    if(ret == ERROR) {
        return -1;
    }

    t.join();
    return 0;
}

很明显,若是do_other_things()函数调用返ERROR, 那么就会直接退出main函数,此时join就不会被调用,因此线程t的资源没有被回收,形成了资源泄露。code

例子二:对象

void test()
{
}

bool do_other_things()
{
}

int main()
{
    std::thread t(test);

    try {
        do_other_things();
    }
    catch(...) {
        throw;
    }
    t.join();
    return 0;
}

这个例子和例子一差很少,若是调用do_other_things()函数抛出异常,那么就会直接终止程序,join也不会被调用,形成了资源没被回收。进程

那么直接在异常捕捉catch代码块里调用join就ok啦。
例子三:ci

void test()
{
}

bool do_other_things()
{
}

int main()
{
    std::thread t(test);

    try {
        do_other_things();
    }
    catch(...) {
        t.join();
        throw;
    }
    t.join();
    return 0;
}

是否是不少人这样操做?这样作不是万无一失的, try/catch块只可以捕捉轻量级的异常错误,在这里若是在调用do_other_things()时发生严重的异常错误,那么catch不会被触发捕捉异常,同时形成程序直接从函数调用栈回溯返回,也不会调用到join,也会形成线程资源没被回收,资源泄露。

因此在这里有一个方法是使用建立局部对象,利用函数调用栈的特性,确保对象被销毁时触发析构函数的方法来确保在主线程结束前调用join(),等待回收建立的线程的资源。

class mythread {
private:
    std::thread &m_t;

public:
    explicit mythread(std::thread &t):m_t(t){}
    ~mythread() {
        if(t.joinable()) {
            t.join()
        }
    }

    mythread(mythread const&) = delete;
    mythread& operate=(mythread const&) = delete;
}

void test()
{
}

bool do_other_things()
{
}

int main()
{
    std::thread t(test);
    mythread q(t);

    if(do_other_things()) {
        return -1;
    }

    return 0;
}

在上面的例子中,不管在调用do_other_things()是发生错误,形成return main函数,仍是产生异常,因为函数调用栈的关系,总会回溯的调用局部对象q的析构函数,同时在q的析构函数里面先判断j.joinable()是由于join操做对于同一个线程只能调用一次,否则会出现错误的。这样,就能够确保线程必定会在主函数结束前被等待回收了。

相关文章
相关标签/搜索