c++中的多线程

使用 std::thread 时需要包含 #include<thread> 头文件,定义了表示线程的类、用于互斥访问的类与方法等。

参考网址:

  • https://blog.csdn.net/liuker888/article/details/46848905
  • https://blog.csdn.net/fengbingchun/article/details/73393229

成员类型和成员函数:

std::thread中主要声明三类函数:(1)、构造函数、拷贝构造函数(拷贝构造函数被禁用,意味着thread不可被拷贝构造,但能被转移(move)或者互换(swap))及析构函数;(2)、成员函数;(3)、静态成员函数(hardware_concurrency,检测硬件并发特性。

构造函数如下:

一些相关的数据结构和存储位置:

    //栈上  
    thread t1(show);   //根据函数初始化执行  
    thread t2(show);  
    thread t3(show);  
    //线程数组  
    thread th[3]{thread(show), thread(show), thread(show)};   
    //堆上  
    thread *pt1(new thread(show));  
    thread *pt2(new thread(show));  
    thread *pt3(new thread(show));  
    //线程指针数组  
    thread *pth(new thread[3]{thread(show), thread(show), thread(show)}); 

  线程初始化(如下实现了多线程传递参数)

void show(const char *str, const int id);
int main()  
{  
    thread t1(show, "hello!", 0);  //三个参数分别为函数名,以及其两个参数
    thread t2(show, "C++!", 1);  
    return 0;  
}  

  join:调用该函数会阻塞当前线程。阻塞调用者(caller)所在的线程直至被join的std::thread对象标识的线程执行结束;

  detach:将当前线程对象所代表的执行实例与该线程对象分离,使得线程的执行可以单独进行。一旦线程执行完毕,它所分配的资源将会被释放。

    • 在任何一个时间点上,线程是可结合的(joinable),或者是分离的(detached)。一个可结合的线程能够被其他线程收回其资源和杀死;在被其他线程回收之前,它的存储器资源(如栈)是不释放的。相反,一个分离的线程是不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放。
    • threads.joinable() 判断线程是否可以join     ;threads.join();//主线程等待当前线程执行完成再退出 ;
    • th.detach();

//脱离主线程的绑定,主线程挂了,子线程不报错,子线程执行完自动退出。  //detach以后,子线程会成为孤儿线程,线程之间将无法通信。 

---------------------------------

  获取CPU核心个数:

n = thread::hardware_concurrency();//获取cpu核心个数 

  原子变量与线程安全:线程之间会有冲突(下面的代码可能存在num++重叠的现象)

  • 互斥量:
#include<iostream>  
#include<thread>  
#include<mutex>  
using namespace std;  
const int N = 100000000;  
int num(0);  
mutex m;  
void run()  
{  
    for (int i = 0; i < N; i++)  
    {  
        m.lock();  
        num++;  
        m.unlock();  
    }  
}  
int main()  
{  
    clock_t start = clock();  
    thread t1(run);  
    thread t2(run);  
    t1.join();  
    t2.join();  
    clock_t end = clock();  
    cout << "num=" << num << ",用时 " << end - start << " ms" << endl;  
    return 0;  
}  

 存在问题:计算速度很慢,原因主要是互斥量加解锁需要时间 。std::mutex

  • 原子变量:
#include<iostream>  
#include<thread>  
#include<atomic>  
using namespace std;  
const int N = 100000000;  
atomic_int num{ 0 };//不会发生线程冲突,线程安全  
void run()  
{  
    for (int i = 0; i < N; i++)  
    {  
        num++;  
    }  
}  
int main()  
{  
    clock_t start = clock();  
    thread t1(run);  
    thread t2(run);  
    t1.join();  
    t2.join();  
    clock_t end = clock();  
    cout << "num=" << num << ",用时 " << end - start << " ms" << endl;  
    return 0;  
}  

  通过原子变量后运算结果正确,计算速度一般。参考std::atomic

但其实只要使用join,可以提升计算的速度

    thread t1(run);  
    t1.join();  //结束才回到主线程
    thread t2(run);  
    t2.join(); 

  ------------------------

时间等待的问题

#include<iostream>  
#include<thread>  
#include<chrono>  
using namespace std;  
int main()  
{  
    thread th1([]()  
    {  
        //让线程等待3秒  
        this_thread::sleep_for(chrono::seconds(3));  
        //让cpu执行其他空闲的线程  
        this_thread::yield();  
        //线程id  
        cout << this_thread::get_id() << endl;  
    });  
    return 0;  
}
  • yield()函数可以用来将调用者线程跳出运行状态,重新交给操作系统进行调度,即当前线程放弃执行,操作系统调度另一线程继续执行;
  • sleep_until()函数是将线程休眠至某个指定的时刻(time point),该线程才被重新唤醒;
  • sleep_for()函数是将线程休眠某个指定的时间片(time span),该线程才被重新唤醒,不过由于线程调度等原因,实际休眠实际可能比sleep_duration所表示的时间片更长。

-------------------------------

线程的交换使用 swap(t1, t2);

线程移动使用thread t2 = move(t1);

原文地址:https://www.cnblogs.com/zhang-qc/p/8671248.html