接上篇 c++标准库:并发(一) —— 高级接口 async()和futrue

thread相关的api可以通过#include <thread>来引入,promise相关的api在#include <future>中。

std::thread 的 join和detach

  • std::async方式启动异步任务不同,std::thread会无条件的在一个独立线程中启动任务并开始执行
    如果希望当前线程等待知道线程t执行结束,那就调用t.join()
  • 如果打算将线程t从母体卸离,使它运行于后台而不受任何控制,那就调用t.detach()
  • 如果线程t的生命周期结束,或者发生了一次Move Assignment时仍未调用join或者detach,程序将终止并调用std::terminal()
  • 进程结束时所有detach的线程奖杯强制结束
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 持有结果和异常

可以在线程中通过 promise.set_valuepromise. set_exception 来为promise对象设置结果或者异常。
在线程任务执行结束后,主线程从promise对象get一个future对象,并通过调用future.get()来获取promise持有的结果中获取最终结果或者抛出异常。

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 打包任务

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;
}

☞ 参与评论