我们称那些可以与其他计算并行执行的计算为任务(task)。线程( thread)是任务在程序中的系统级表示。若要启动一个与其他任务并发执行的任务,我们可以构造一个std::thread(在< thread>中)并将任务作为它的实参。这里的任务是以函数或函数对象的形式出现的:

    1. void f(); //函数
    2. struct F{
    3. void operator()(); //F调用运算符(见3.4.3节)
    4. };
    5. void user()
    6. {
    7. thread t1{f}; //f()在独立的线程中执行
    8. thread t2{F()}; //F()()在独立的线程中执行
    9. t1.join(); //等待t1完成
    10. t2.join(); //等待t2完成
    11. }

    join()保证我们在线程完成后才退出user(),其中“join”的意思是“等待线程结束”。
    一个程序的所有线程共享单一地址空间。在这一点上线程与进程不同,进程间通常不直接共享数据。由于共享单一地址空间,因此线程间可通过共享对象(见5.3.4节)相互通信。通常通过锁或其他防止数据竞争(对变量的不受控制的并发访问)的机制来控制线程间通信。
    编写并发任务可能非常棘手。任务f(函数)和F(函数对象)可能会写成如下的形式:

    1. void f(){cout<<"hello";}
    2. struct F
    3. {
    4. void operator()(){cout<<"Parallel World!\n";}
    5. };

    这是一个典型的严重错误:在本例中,fF()都使用了对象cout,但没有采取任何形式的同步措施。因此,输出结果将是不可预测的,而且程序每一次执行都可能得到不同结果,毕竟两个任务中的操作的执行顺序根本无法确定。程序可能会产生下面这样“奇怪的”输出
    PaHerallllel o World!
    在定义一个并发程序的任务时,我们的目标是保持任务的完全隔离,唯一的例外是任务间通信的部分,这种通信应该以一种简单而明显的方式进行。思考一个并发任务的最简单的方式是把它看作一个可以与调用者并发执行的函数。为此,我们只需传递实参、获取结果并保证两者不会同时使用共享数据(不存在数据竞争)即可。