C++ concurrency in action (二)

本文探讨了C++中用于并发编程的同步机制——条件变量,包括其在异常处理和多个线程同时等待场景下的应用。通过实例展示了如何使用条件变量实现线程安全队列,并讲解了当条件变量抛出异常时如何处理,以及如何在多个线程等待同一事件时使用std::condition_variable进行封装。
摘要由CSDN通过智能技术生成

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

结果为
errorn


使用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;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值