C++11多线程

C++11多线程

C++11标准,头文件thread,可用于简单地创建一个可单独执行的执行单元,用gcc编译器在编译的时候因为Linux标准库中是不默认包含pthread.a静态库的,需要在编译选项后面添加-lpthread选项

# 比如程序为main.cpp,要生成main_exe可执行文件
# gcc命令为
# 需要在后面添加lpthread选项
g++ -o main_exe main.cpp -lpthread 

构造函数

thread用于创建一个单线程的对象类型为thread,可用其定义线程对象,其构造函数中传入的数值有三种

  1. 实现了()重载运算符的类
  2. 一个函数句柄,或者说函数指针
  3. lamda表达式

一个可执行的执行单元与一系列参数列表

// 构造函数
    template<typename _Callable, typename... _Args,
	     typename = _Require<__not_same<_Callable>>>
      explicit
      thread(_Callable&& __f, _Args&&... __args)
      {
	static_assert( __is_invocable<typename decay<_Callable>::type,
				      typename decay<_Args>::type...>::value,
	  "std::thread arguments must be invocable after conversion to rvalues"
	  );

三个case

__Callable为函数指针,

// __Callable为函数指针
thread t(funname, 参数列表...);  // 形参类型为引用时,不要直接传入,需要用std::ref(参数)

__Callable为类

class Callable{
    .....
public:
    void operator()(参数列表){
        .....
    }
}

thread t(Callable(), 参数列表...);

__Callable为lamda

thread t([捕获列表](参数列表){....}, 参数列表);

// 或者拆开来写
auto handle = [捕获列表](参数列表){....};
thread t1(handle, 参数列表);

启动

一个thread对象一旦定义,就需要被使用,或者说执行,若只定义了一个线程对象,而不执行的话,就会在调用thread的析构函数时抛出std::terminate()异常,这个错误可以被try...catch捕获

~thread(){
    if(joinable()){
        std::terminate(); // 抛出terminate错误
    }
}

joinableAPI返回bool值,如果线程对象已经开始执行,返回false,如果还未开始执行,则返回true,启动通过join()detach()API调用控制

  • join()调用,比如在主线程中调用t.join(),主线程会等待当前线程执行完毕之后再继续执行后面的语句
  • detach()调用,当前线程从创建线程中分离出来,独立执行,创建线程不会被他阻塞,并且在主线程中,程a序的退出不会因为分立线程还未执行完毕而稍作停留,一切照常

验证场景,从主线程冲join一个线程,然后从join的线程中detach线程,让他们分别在命令行输出信息,可以看到main线程会等待join线程执行完毕之后才执行,而detach则是分离的,验证代码如下,执行可以看到结果

#include<iostream>
#include<thread>

using namespace std;

void detach_callable(){
    int i;
    for(i=0;i<5;i++){
        cout<<"detach thread:"<<"[my step is"<<i<<"]"<<endl;
    }
}

void join_callable(thread &t){
    if(!t.joinable())
        std::terminate();
    else{
        t.detach();
        int i;
        for(i=0;i<5;i++){
            cout<<"join thread:"<<"[my step is"<<i<<"]"<<endl;
        }
    }
}

int main(int argc, char *argv[]){

    thread t1(detach_callable);
    thread t2(join_callable, std::ref(t1));

    t2.join(); // main thread wait for thread t2

    int i;
    for(i = 0; i<5 ; ++i){
        cout<<"main thread:"<<"[my step is"<<i<<"]"<<endl;
    }

    return 0;
}
detach thread:[my step isjoin thread:[my step is0]0]

join thread:[my step is1]
join thread:[my step is2]
join thread:[my step is3]
join thread:[my step is4]
detach thread:[my step is1]
detach thread:[my step is2]
detach thread:[my step is3]
detach thread:[my step is4]
main thread:[my step is0]
main thread:[my step is1]
main thread:[my step is2]
main thread:[my step is3]
main thread:[my step is4]

线程何时go dead?

线程是一个单元,线程之间能共享进程的内存空间,所以线程是在进程的基础之上的一个执行模块,依靠进程支撑,他又下面几种死法

  1. Callable执行完毕,安乐dead,线程退出
  2. 主线程已经执行完毕,直接杀死其它线程,线程go dead
  3. 因为运行异常导致进程退出,致使线程go dead

复活是不可能复活的,横竖都是一个go dead

其它API

  • get_id返回线程的id

  • natvie_handle返回本地底层函数句柄

  • hardware_concurrency返回CPU最多可支持的并发线程数,即同一个时间戳能一起运行的最大线程数

#include<thread>
#include<iostream>

using namespace std;

int main(int argc, char* argv[]){
    cout<<thread::hardware_concurrency()<<" threads execute concurrently"<<endl;
    return 0;
}
8 threads execute concurrently
  • swap交换两个线程的句柄,与a和b的值交换一样
#include <iostream>
#include <thread>
#include <chrono>
 
void foo()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}
 
void bar()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}
 
int main()
{
    std::thread t1(foo);
    std::thread t2(bar);
 
    std::cout << "thread 1 id: " << t1.get_id() << '\n'
              << "thread 2 id: " << t2.get_id() << '\n';
 
    std::swap(t1, t2); // 交换t1 t2的句柄
 
    std::cout << "after std::swap(t1, t2):" << '\n'
              << "thread 1 id: " << t1.get_id() << '\n'
              << "thread 2 id: " << t2.get_id() << '\n';
 
    t1.swap(t2);		// 另外一种交换方式
 
    std::cout << "after t1.swap(t2):" << '\n'
              << "thread 1 id: " << t1.get_id() << '\n'
              << "thread 2 id: " << t2.get_id() << '\n';
 
    t1.join();
    t2.join();
}
thread 1 id: 2
thread 2 id: 3
after std::swap(t1, t2):
thread 1 id: 3
thread 2 id: 2
after t1.swap(t2):
thread 1 id: 2
thread 2 id: 3
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值