The thread-related api can be introduced via #include <thread>, and the promise-related api is in #include <future>.

std::thread’s join and detach

  • Unlike the std::async method of starting asynchronous tasks, std::thread will unconditionally start a task in a separate thread and begin execution If you want the current thread to wait until it knows that thread t has finished executing, then call t.join()
  • If the intention is to detach thread t from the parent so that it runs in the background without any control, then t.detach() is called
  • If the life cycle of thread t ends, or if a Move Assignment occurs while still not calling join or detach, the program will terminate and call std::final()
  • All detach threads will be forced to end when the process ends
1
2
3
4
5
6
7
8
//Join,会等到线程中的异步任务执行结束
//两个线程在创建后会立即同时开始异步任务,这俩符号交替打出
void TestJoin(){
    std::thread t1(doSomething, '+');
    std::thread t2(doSomething, '-');
    t1.join();
    t2.join();
}
1
2
3
4
5
6
7
8
9
//detach,程序不会管线程是否执行结束,直接结束
void TestDetach(){
    std::thread t1(doSomething, '+');
    std::thread t2(doSomething, '-');
    t1.detach();
    t2.detach();
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    std::cout << "job done!" << std::endl;
}

std::promise holds results and exceptions

You can set results or exceptions for a promise object in a thread by using promise.set_value and promise.set_exception. After the thread task is executed, the main thread gets a future object from the promise object and gets the final result or throws an exception from the results held by the promise by calling future.get().

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void doSomethingPromise(std::promise<std::string> &p){
    try{
        std::srand(324312);
        int rand = std::rand() % 100;
        std::cout << "current thread:" << std::this_thread::get_id() << std::endl;
        if(rand>50){
            p.set_value("promise resolve!" + std::to_string(rand));
        } else {
            throw std::runtime_error("promise reject " + std::to_string(rand));
        }
    } catch(...){
        p.set_exception(std::current_exception());
    }
}

// Promise,可以resolve、reject
// Promise不仅可以用在多线程场景中,也可以用来在单线程场景持有一个结果或者异常,放后面处理
void TestPromise(){
    std::promise<std::string> p;
    // 注意这里传递promsie的引用进去,要用std::ref(p),而不能 &p
    std::thread t(doSomethingPromise, std::ref(p));
    t.detach();
    std::future<std::string> f = p.get_future();
    try{
        std::cout << f.get() << std::endl;
    } catch(std::exception &e){
        std::cout << e.what() << std::endl;
    }
}

std::packaged_task Packaged task

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
double compute(int a, int b){
    std::cout << " in thread " << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(a+b));
    return a+b;
}
//打包任务,用于在线程池中控制任务启动等操作
void TestPackagedTask(){
    std::packaged_task<double(int, int)> pt(compute), pt2(compute);
    std::future<double> f = pt.get_future(), f2 = pt2.get_future();
    std::cout << " start packaged task " << std::endl;
    //打包好的任务一般会放到别处,例如线程池中去执行,这里可以利用thread或者异步launch的future模拟一下
    //多个打包好的任务,会并行运行
    std::thread t1([&]{pt(1, 4);});
    std::thread t2([&]{pt2(1, 4);});
    t1.detach();
    t2.detach();
    // std::future<void> _f1 = std::async(std::launch::async, [&]{pt(1, 4);});
    // std::future<void> _f2 = std::async(std::launch::async, [&]{pt2(1, 4);});
    // _f1.get();
    // _f2.get();
    std::cout << " packaged task result: " <<  f.get() << " result2:" << f2.get() << std::endl;
}

Reference https://www.zoucz.com/blog/2021/06/09/91711c10-c875-11eb-9fe7-534bbf9f369d/