C++ 并发编程(同步)
条件变量
条件变量的使用见c++11 实现线程安全队列
future
future
的提出是为了解决当一个事件发生并没有那么频繁,使用条件变量会显得过于麻烦的场景。例如乘坐飞机和上课的频繁程度。
在c++中有两种实现
std::future<>
std::shared_future<>
//区别类似于std::unique_ptr<>与std::shared_ptr<>
该类不可拷贝
std::sync
std::sync
参数传递规则和std::bind
相同。
#include<thread>
#include<chrono>
#include<future>
#include<iostream>
int accumulate(int start,int end){
int sum=0;
for(int i = start;i<=end;i++)
sum+=i;
std::this_thread::sleep_for(std::chrono::seconds(2));
return sum;
}
int main(){
std::future<int> the_answer = std::async(accumulate,10,20);
std::cout<<"answer is:"<<the_answer.get()<<std::endl;
return 0;
}
同时还有两个附加参数
std::launch::asycn
,单独开启一个线程进行异步处理std::launch::deferred
,调用get
时才执行
默认为两者的或std::launch::asycn|std::launch::deferred
,即,由库自己觉得如何运行任务
#include<thread>
#include<chrono>
#include<future>
#include<iostream>
int accumulate(int start,int end){
int sum=0;
for(int i = start;i<=end;i++)
sum+=i;
std::this_thread::sleep_for(std::chrono::seconds(2));
return sum;
}
int main(){
std::future<int> the_answer = std::async(std::launch::deferred|std::launch::async,accumulate,10,20);
std::cout<<"answer is:"<<the_answer.get()<<std::endl;
return 0;
}
std::packaged_task
将std::future
和一个可调用对象绑定,其为一个可调用对象。无法拷贝
#include<thread>
#include<chrono>
#include<future>
#include<list>
#include<iostream>
std::list<std::packaged_task<int()>> task_list;
int shut_down;
std::mutex mutex_;
void thread1(){
std::packaged_task<int()>task;
while(!shut_down){
std::this_thread::sleep_for(std::chrono::seconds(2));
{
std::lock_guard<std::mutex> lk(mutex_);
while(task_list.size()){
// packaged_task 无法被拷贝
auto task = std::move(task_list.front());
task_list.pop_front();
task();
}
}
}
}
int main(){
std::thread t1(thread1);
std::packaged_task<int()> pack([]()->int {std::cout<<"are you ok?";return 1;});
std::future<int> future = pack.get_future();
{
std::lock_guard<std::mutex> lk(mutex_);
task_list.push_back(std::move(pack));
}
std::cout<<future.get()<<std::endl;
// 省事,没别的
shut_down = 1;
t1.join();
return 0;
}
std::primise
可以通过设置的方式,来使得关联的future
变为ready
状态。future只能使用一次、primise只能获取一次future
#include <iostream>
#include <future>
#include <chrono>
void thread1(std::future<int> &f,bool& shut_down){
auto val = f.get();
std::cout<<"I got"<<val<<std::endl;
}
int main()
{
std::promise<int> p;
std::future<int> f = p.get_future();
bool shut_down = false;
std::thread t(thread1,std::ref(f),std::ref(shut_down));
std::this_thread::sleep_for(std::chrono::seconds(1));
p.set_value(2);
shut_down = true;
t.join();
return 0;
}
异常处理
在使用future
发生异常时,异常会被std::async
通过get
抛出到主线程。
例如
#include <iostream>
#include <future>
#include <chrono>
#include<cmath>
double square_root(double x){
if(x<0){
throw std::out_of_range("x<0");
}
return sqrt(x);
}
int main()
{
std::future<double> f = std::async(std::launch::async,square_root,-1);
std::cout<<"the resutl is"<<f.get()<<std::endl;
return 0;
}
结果为
使用std::primise
来抛出异常
try{
some_primise.set_value(calculate_value());
}
catch(...){
//std::current_exception(),抛出当前异常
some_promise.set_exception(std::current_exception());
}
多个线程同时等待
std::future
只能有一个对象,当需要多个线程等待一个事件时,可以使用标准库提供的std::shared_future
来对std::future
进行封装(可拷贝对象、线程安全)。
std::promise<int> p;
std::future<int> f(p.get_future());
std::shared_future<int> sf(std::move(f));
assert(!f.valid())//future is invalid now;
assert(sf.valie())//sf is valid now;