2.3 转移线程的所有权

std::move转移线程的所有权

  与std::ifstream 与 std::unique_ptr一样,std::thread也是可移动的,而非可复制的。这意味着一个特定的执行线程的所有权可以在std::thread实例之间移动,但是,在任意时刻,只有一个std::thread对象与某个特定的线程相关联。

void some_function();
void some_other_function();
int main()
{
    std::thread t1(some_function);    // 启动一个新线程运行some_function,并与t1相关联
    std::thread t2 = std::move(t1);   // 调用std::move()来显示转移线程所有权

    /* 此时:
     * t1不再拥有相关联的执行线程
     * t2与运行some_function的线程相关联
     */

    t1 = std::thread(some_other_function); // 启动一个新线程执行some_other_function,并与一个临时的std::thread对象相关联,再将所有权转移到t1;
    std::thread t3;      // t3为默认构造的std::thread对象,没有与任何执行线程相关联
    t3 = std::move(t2);   // 将与t2相关联的线程的所有权转移到t3
    
    /* 此时:
     * t1运行some_other_function的线程现在相关联
     * t2不再拥有相关联的执行线程
     * t3与运行some_function的线程现在相关联
     */

    t1 = std::move(t3);    // 错误:欲将与t3相关联的线程的所有权转移到t1,但是t1已经有了一个相关联的线程(运行着some_other_function),所以会调用std::terminate()来终止程序
    return 0;
}

修改后:

void some_function();
void some_other_function();
int main()
{
    std::thread t1(some_function);
    std::thread t2 = std::move(t1);

    t1 = std::thread(some_other_function); 

    std::thread t3;
    t3 = std::move(t2); 

    t1.detach();     // 调用detach()后,t1不再与任何线程相关联
    t1 = std::move(t3);    // 正确:将与t3相关联的线程的所有权转移到t1
    t1.join();
    return 0;
}   

从函数返回std::thread

void some_function();
std::thread f()
{
    return std::thread(some_function);
}

void some_other_function();
std::thread g()
{
    std::thread t(some_other_function);
    return t;  
}

  也可以把线程所有权转移到函数中,但是函数只能以值的形式接受std::thread的实例作为其中一个参数

void f2(std::thread t);
void g2() 
{
    // 调用方式1
    void some_function();
    f2(std::thread(some_function));

    // 调用方式2
    std::thread t(some_function);
    f2(std::move(t));
}

自定义线程管理类

void do_something(int value);
void do_something_in_current_thread();

class scoped_thread
{
public:
    explicit scoped_thread(std::thread t_)
        : t(std::move(t_))
    {
        if (!t.joinable())// 判断线程是否可结合
            throw std::logic_error("No thread");// 引发异常
    }

    ~scoped_thread()
    {
        t.join();// 等待线程结束
    }

    scoped_thread(scoped_thread const&) = delete;
    scoped_thread& operator=(scoped_thread const&) = delete;
private:
    std::thread t;
};

struct func 
{
    int& i;
    func(int& i_):i(i_){}

    void operator()()
    {
        for (unsigned j = 0; j < 1000000; j++)
        {
            do_something(i);
        }
    }
};

void f()
{
    int some_local_state;
    scoped_thread t(std::thread(func(some_local_state)));// 将运行函数func(some_local_state)的线程所有权转移至scoped_thread对象t内 

    do_something_in_current_thread();
}
    

生成一批线程并等待它们完成

void do_work(unsigned id);
void f()
{
    std::vector<std::thread> threads;
    for (unsigned i = 0; i < 20; i++)
    {
        threads.push_back(std::thread(do_work, i)); // 生成线程
    }

        // 轮流在每个线程上调用join()    
        std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));    
}

 

posted on 2021-05-25 15:06  天官赐福  阅读(158)  评论(0)    收藏  举报