zoukankan      html  css  js  c++  java
  • C++11 之 并发编程 (一)

      未来芯片制造,如果突破不了 5nm 极限,则 CPU 性能的提升,可能会依赖于三维集成技术,将多个 CPU 核集成在一起,使得多核系统越来越普遍。

      以前的 C++ 多线程,一是受限于平台,多借助于封装好的 APIs 来完成,例如:POSIX threads,Windows threads 等;二是受限于单核系统,本质上都是“伪多线程”:通过线程调度,使得单核系统进行任务的切换,形成多线程的假象。

      新的 C++11 标准,在语言层面上实现了多线程,其库中提供了相关组件,使得跨平台编写多线程 cpp 程序成为可能,最终能够在多核系统中实现真正的并行计算

    1  并发 (concurrency)

    1.1 并发与并行

      计算机中的并发,指的是在单一系统中,同时执行多个独立的活动。对于多核系统,它们在同一时刻进行的活动,则称为并行

      通俗的理解:当有两个人都在边吃饭边看电视时,对于一个人而言,吃饭和看电视就是并发,对于两个人而言,他们在同一时刻进行的活动,可称为并行。

     1) 单核的任务切换 (task switching)

     

     2) 双核的并行执行 (parallel execution)

      

     1.2 线程与进程

      如果将进程比作一套房子,那么住在房子里的人,其从事的各种活动 (比如,厨房做饭,客厅吃饭,卧室看电视),就是一个个的线程。现在又搬来一个人,则当两个人都在房子里,做着各自的活动时,程序便由以前的单线程变为了多线程

      有的房间 (比如客厅) 两个人都可以同时进出,这代表着进程中某些内存空间是共享的,每个线程都可以使用这些共享内存。有的房间 (比如厕所) 一次只能容纳一个人,先进去的把门锁上,后到的人看到锁,就在外面等待,直到先进去的人把锁打开,这就是“互斥核” (mutex)

      在应用程序中,具体利用到并发编程的,一是多进程并发,二是多线程并发,如下图:   

               

              (1) 多进程并发                     (2) 多线程并发

    2  程序示例

      实现多线程需要 1) 头文件 <thread>   2) 单独的线程函数 threadFunc()   3)线程对象 thread t(threadFunc)   4)等待线程 join()

    #include <thread>
    #include <iostream>
    
    void threadFunc()
    {
        std::cout << "This is a thread!" << std::endl;
    }
    
    int main()
    {
        std::thread t(threadFunc);
        t.join();
        
        std::cout << "This is main program!" << std::endl;
        
        return 0;
    }

      输出结果为:

    This is a thread!
    This is main program!

       当使用 t.detach() 来代替 t.join() 时,主线程 main 不会等待新线程 t(threadFunc),只会独自运行到程序结束。

    3  任务代替线程

    3.1  两个问题

    1) 线程耗尽 (exhaustion)

     软件线程是一种有限的资源,当创建的线程数量多于系统所能够提供的,一个异常 std::system_error 就会抛出,程序便会终止。

    2) 线程超额 (oversubscription)

     当等待运行的线程 (ready-to-run) 多于系统硬件线程 (hardware threads) 时,线程调度器会为每个软件线程在硬件线程上分配时间片 (time-slice)。若一个线程的时间片结束,另一个线程的时间片刚开始时,上下文的切换 (context switch) 就会被执行。对于多核系统,当线程从一个 CPU 被切换到另一个 CPU 中时,会造成很大的资源消耗。

    3.2  基于任务 (task-based)

      基于线程编程 (thread-based),必须手动管理上面的两个问题,增加了编程的难度。

      基于任务编程 (task-based),通过 std::async,可将问题交由 C++标准库处理,简化了程序。

      1)  头文件 <future> 

      2) 单独的任务函数 taskFunc1taskFunc2 

      3) 异步任务对象 auto fut1 = std::async(taskFunc1) 

      4) 获取任务函数返回值 fut1.get()

    #include <iostream>
    #include <thread>
    #include <future>
    
    std::string taskFunc1()
    {
        std::string str = "This is task1";
        return str;
    }
    
    std::string taskFunc2()
    {
        std::string str = " and task2";
        return str;
    }
    
    int main()
    {
        auto fut1 = std::async(taskFunc1);
        auto fut2 = std::async(taskFunc2);
    
        std::cout << fut1.get() + fut2.get() << std::endl << "This is main program" << std::endl;
    
        return 0;
    }

       输出结果为:

    This is task1 and task2
    This is main program

    小结:

     1) thread-based programming needs manual management of thread exhaustion, oversubscription, load balancing, and adaptation to new platforms.

     2) task-based programming handles most of these issues via std::async with the default launch policy

    参考资料:

      <C++ Concurrency in Action> chapter 1

      <Effecctive Modern C++>  chapter 7

  • 相关阅读:
    在浏览器地址栏输入url的后的过程
    webpack的理解
    Vuex总结
    vue 中引用better-scroller实现横向轮播
    vue中类似于jq中的ele.addClass('class').siblings().removeClass('class')效果
    vue中星级判断函数
    ---redux---
    ---react-redux----
    ----flux----
    React组件
  • 原文地址:https://www.cnblogs.com/xinxue/p/5778270.html
Copyright © 2011-2022 走看看