如何进行线程管理

1.启动线程(创建线程)

  • 普通正常启动(构造临时对象)

自己的Demo,参考代码如下:

#include <thread>
#include <iostream> 
void do_something();
void do_something_else();
void do_something(){
    std::cout<<"cherno love c++"<<std::endl;
}
void do_something_else(){
    std::cout<<"welcome to my program world"<<std::endl;
}
class my_first_thread{
    public:
    void operator()()const{
        do_something_else();
    }
    public:
    my_first_thread() noexcept=default;
    // my_first_thread(const my_first_thread&other)=delete;
    my_first_thread &operator=(const my_first_thread &other)=delete;
    ~my_first_thread()=default;
};
int main(int argc,char **argv){
    do_something();
    my_first_thread m;
    std::thread t(m);
    t.join();
    return 0;
}

运行结果:

cherno love c++
welcome to my program world 

上述代码通过构造类的临时对象,将该临时对象作为线程构造函数参数,完成线程的创建。

  • 非正常启动(启动失败)

启动失败参考代码如下:

#include <thread>
#include <iostream> 
void do_something();
void do_something_else();
void do_something(){
    std::cout<<"cherno love c++"<<std::endl;
}
void do_something_else(){
    std::cout<<"welcome to my program world"<<std::endl;
}
class my_first_thread{
    public:
    void operator()()const{
        do_something_else();
    }
    public:
    my_first_thread() noexcept=default;
    // my_first_thread(const my_first_thread&other)=delete;
    my_first_thread &operator=(const my_first_thread &other)=delete;
    ~my_first_thread()=default;
};
int main(int argc,char **argv){
    do_something();
    // my_first_thread m;
    // std::thread t(m);
    std::thread t(my_first_thread());
    t.join();
    return 0;
}

上述代码是将运算符重载函数作为线程构造函数参数,导致线程创建失败。

  • 其他方式启动线程(Lambda表达式)

对上述代码修改,参考代码如下:

#include <thread>
#include <iostream> 
void do_something();
void do_something_else();
void do_something(){
    std::cout<<"cherno love c++"<<std::endl;
}
void do_something_else(){
    std::cout<<"welcome to my program world"<<std::endl;
}
class my_first_thread{
    public:
    void operator()()const{
        do_something_else();
    }
    public:
    my_first_thread() noexcept=default;
    // my_first_thread(const my_first_thread&other)=delete;
    my_first_thread &operator=(const my_first_thread &other)=delete;
    ~my_first_thread()=default;
};
int main(int argc,char **argv){
    do_something();
    std::thread t([](){
        do_something_else();
    });
    t.join();
    return 0;
}

运行结果:

cherno love c++
welcome to my program world

2.detach

示例代码参考如下:

​
#include <thread>
#include <iostream>
class danger_thread{
    private:
    unsigned int value;
    public:
    danger_thread() noexcept=default;
    danger_thread(const unsigned int value):value(value){};
    // danger_thread(const danger_thread &other)=delete;
    danger_thread &operator=(const danger_thread &other)=delete;
    ~danger_thread()=default;
    public:
    void operator()(){
        for(unsigned int i=0;i<value;i++){
            std::cout<<i<<"."<<"chrno love threads program"<<std::endl;
        }
    }
};
void thread_start(){
    int local_value=10;
    std::thread t{danger_thread(local_value)};
    t.detach();
}
int main(int argc,char **argv){
    thread_start();
    return 0;
}

​

运行结果:

detach的作用:不阻塞线程。

具体区别图(join与detach函数):

  • join

主线程等待新线程完成后,才继续运行。 

  • detach

主线程并未等待线程完成,而是自顾自地运行。 

3.异常处理线程等待

#include <iostream>
#include <thread>
#include <exception>
void do_something_else(){
    std::cout<<"cherno"<<std::endl;
}
struct danger_thread{
    unsigned int &value;
    danger_thread(unsigned int value):value(value){}
    void operator()(){
        for(unsigned int i=0;i<value;i++){
            std::cout<<i<<":"<<"I love c++ Porgram"<<std::endl;
        }
    }
};
void thread_start(){
    unsigned int local_value=10;
    danger_thread my_thread(local_value);
    std::thread t(my_thread);
    try
    {
        do_something_else();
    }
    catch(...)
    {
        t.join();
        throw;
    }
    t.join();
}
int main(int argc,char *argv[]){
    thread_start();
    return 0;
}

在捕捉到异常时添加join,并在外层添加join,保证了异常处理时,正确的处理方式。

  • 使用RAII机制重构线程构造

代码如下:

#include <iostream> 
#include <thread>
void do_something_else(){
    std::cout<<"cherno"<<std::endl;
}
class thread_guard{
private:
    std::thread &t;
public:
    explicit thread_guard(std::thread &t_):t(t_){}
    ~thread_guard(){
        if(t.joinable())
            t.join();
    }
    thread_guard(const thread_guard &other)=delete;
    thread_guard &operator=(const thread_guard &other)=delete;
};
struct danger_thread{
    unsigned int value;
    danger_thread(unsigned int value):value(value){}
    void operator()(){
        for(unsigned int i=0;i<value;i++){
            std::cout<<i<<":"<<"I love c++ Program"<<std::endl;
        }
    }
};
void thread_start(){
    unsigned int local_value=10;
    danger_thread my_thread(local_value);
    std::thread t(my_thread);
    thread_guard guard(t);
    do_something_else();
}
int main(int argc,char **argv){
    thread_start();
    return 0;
}

思想:主要在析构时进行join

RAII机制

RAII即资源分配即初始化。

RAII原理:

资源的使用通常是分为三个步骤:

  • 获取资源
  • 使用资源
  • 释放资源

简单来说,RAII主要是为释放资源做工作的,即无需人工释放,而是靠操作系统自动回收。

RAII的应用:

RAII主要应用于互斥锁,保护共享资源。

4.线程构造函数传递参数

  • 普通函数传参

示例代码:

void func(int i,const std::string &s);
const int maxn=1024;
void thread_start(){
    char buffer[maxn];
    std::thread t(func,5,"hello");
}

注意:在传递参数时一定要传入与形参一样形式的参数。 

总结:普通函数传参顺序依次是函数、参数。

  • 类函数传参(无参数)
class Person{
public:
    void do_something();
};
Person person;
std::thread t(&Person::do_something,&person);
  • 类函数传参(有参数): 
class Person{
public:
    void do_something(int i);
};
Person person;
int num(10);
std::thread t(&Person::do_something,&person,num);

 总结类函数传参顺序依次是类函数地址、临时类实例地址、其他参数。

移动线程:

unique_ptr支持移动构造

示例代码:

class big_object;
void process_big_object(std::unique_ptr<big_object>);
std::unique_ptr<big_object>p(new big_object);
p->prepare_data(12);
std::thread__ptr t(process_big_object,std::move(p));

流程如图所示:

线程与unique一样支持移动。 

5.Scoped_thread实现

Scoped_thread类实现,代码如下:

#include <thread>
#include <iostream>
#include <exception>
#include <excpt.h>
void do_something(int value){
    for(int i=0;i<value;i++){
        std::cout<<i<<":"<<"I love c++ Program"<<std::endl;
    }
}
void do_something_else(){
    std::cout<<"cherno"<<std::endl;
}
class scoped_thread{
private:
    std::thread t;
public:
    scoped_thread(std::thread &t_):t(std::move(t_)){
        if(!t.joinable())
            throw std::logic_error("no thread");
    }
    ~scoped_thread(){
        t.join();
    }
    scoped_thread(const scoped_thread &other)=delete;
    scoped_thread&operator=(const scoped_thread &other)=delete; 
};
struct func{
    unsigned int value;
    func(unsigned int value):value(value){}
    void operator()(){
        do_something(value);
    }
};
void thread_start(){
    unsigned int local_value=10;
    std::thread t([local_value](){
        do_something(local_value);
    });
    scoped_thread my_thread(std::ref(t));
    do_something_else();
}
int main(int argc,char *argv[]){
    thread_start();
    return 0;
}

运行结果:

cherno
0:I love c++ Program
1:I love c++ Program
2:I love c++ Program
3:I love c++ Program
4:I love c++ Program
5:I love c++ Program
6:I love c++ Program
7:I love c++ Program
8:I love c++ Program
9:I love c++ Program 

总结:Scoped_thread采用RAII机制,支持线程移动构造。 

补充:智能指针的头文件是<memory> 

完整的Scoped_thread实现如下:

#include <thread>
class joining_thread{
private:
    std::thread t;
public:
    joining_thread() noexcept=default;
    template<typename Callable,typename ...Args>//变参模版
    //变参模版与std::forward移动函数
    explicit joining_thread(Callable &&func,Args&&...args):t(std::forward<Callable>(func),std::forward<Args>(args)...){}
    explicit joining_thread(std::thread t_)noexcept:t(std::move(t_)){}
    joining_thread(joining_thread &other)noexcept:t(std::move(other.t)){}
    joining_thread &operator=(std::thread &t_)noexcept{
        if(joinable())
            join();
        t=std::move(t_);
        return *this;
    }
    joining_thread &operator=(joining_thread &other)noexcept{
        if(joinable())
            join();
        t=std::move(other.t);
        return *this;
    }
    ~joining_thread(){
        if(t.joinable())
           t.join();
    }
    void swap(joining_thread &other)noexcept{
        t.swap(other.t);
    }
    std::thread::id get_id() const noexcept{
        return t.get_id();
    }
    bool joinable()const noexcept{
        return t.joinable();
    }
    void join(){
        t.join();
    }
    void detach(){
        t.detach();
    }
    std::thread &as_thread()noexcept{
        return t;
    }
    const std::thread &as_thread()const noexcept{
        return t;
    }
};

量产线程,等待完成

代码如下:

void do_work(unsigned int id);
void f(){
    std::vector<std::thread>threads;
    for(unsigned int i=0;i<20;i++){
    threads.push_back(std::thread(do_work,i));
    }
std::for_each(threads.begin(),threads.end(),std::mem_fn(&std::thread::join));
}

6.实战(并行版本的求和)(自己实现)

代码如下:

#include <iostream>
#include <thread>
#include <vector>
#include <functional>

#define NUM_THREAD 10 

template <typename Iterator, typename T>
T & my_sum(Iterator begin, Iterator end, T &init){
    unsigned const long length = std::distance(begin, end);
    if(length == 0)
        throw std::logic_error("can not calculate sum");
    for(auto iter = begin; iter!=end; iter++){
        init += *iter;
    }
    return init;
}
template <typename Iterator, typename T>
struct sum_thread{
    void operator()(Iterator begin, Iterator end, T &result){
        result = my_sum(begin, end, result);
    }
};
template <typename Iterator, typename T>
T parallel_sum(Iterator begin, Iterator end, T init){
    unsigned const int thread_numbers = NUM_THREAD;
    unsigned const long length = std::distance(begin, end);
    if(length == 0)
        return init;
    const int block_size = length/thread_numbers;
    std::vector<T> results(thread_numbers);
    std::vector<std::thread> threads(thread_numbers);
    Iterator block_start = begin;
    Iterator block_end = begin;
    for(unsigned int i = 0; i < thread_numbers-1; i++){
        std::advance(block_start, block_size);
        threads[i] = std::thread(sum_thread<Iterator, T>(), 
                                block_start, 
                                block_end,
                                results[i]);
        block_start = block_end;
    }
    threads[thread_numbers-1] = std::thread(sum_thread<Iterator, T>(),
                                            block_start,
                                            end,
                                            results[thread_numbers-1]);
    std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
    // std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
    return my_sum(results.begin(), results.end(), 0);
}

  • 46
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱喝牛奶的奶牛ovo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值