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/