zoukankan      html  css  js  c++  java
  • 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);

  • 相关阅读:
    jvm的概述
    关于请求中的一些小知识点
    对react项目进行进一步的修饰
    java基于token进行登录超时检验和有效性校验
    react获取文本框的值
    redis数据库的缓存击穿和缓存穿透
    centos克隆虚拟机
    Java中的第三大特性-多态性
    java中String类的使用
    Maven更换阿里源与仓库地址
  • 原文地址:https://www.cnblogs.com/zhang-qc/p/8671248.html
Copyright © 2011-2022 走看看