白话《C++》第12章并发,Page532 共享异步存根 使用shared_future的例子(洗车)

准备头文件

完整代码:

#include <iostream>

#include <string>
#include <sstream>

#include <ctime>
#include <random>

#include <chrono>
#include <future>

#include <thread>
#include <mutex>


using namespace std;

//加了锁的cout单例定义
struct COutWithMutex
{
public:
    static COutWithMutex& Get()
    {
        static COutWithMutex instance;
        return instance;
    }

    void PrintLn(string const& line)
    {
        //锁守护的作用范围,是这个代码块
        lock_guard <mutex> g(_m);
        cout << line << endl;
    }

private:
    /* 允许程序员明确在结构或类定义中指明这家伙的
    默认初始化工作内容,就是什么也不做,
    请编译器自行处理去吧。其方法是写上默认构造函数,
    不实现它,只是将它声明为"default(默认的)" */
    COutWithMutex() = default;
    mutex _m;
};

/*接着是洗车过程。假设洗车需要五个步骤,
每个步骤所花费的时间随机生成,以示公平:*/
int get_desc_id(string const& desc)
{
    int id = 0;
    for(auto c : desc)
    {
        //求字符串中各字符的累加值。
        id += static_cast<int>(c);
    }
    return id;
}

//返回所有洗车步骤的总用时。
int Washing(string const desc)
{
    int total(0);

    int id = get_desc_id(desc);
    //以 time(nullptr) + id为种子,再使用数学算法计算出随机数
    mt19937 rd(time(nullptr) + id);

    for(int i = 0; i < 5; ++i)
    {
        // rd() % 10 产生的随机数在[1, 9]之间
        int seconds = 1 + (rd() % 10);

        stringstream ss;
        ss << "[洗车房] - 正在执行清洗" << desc << "的第"
        << i + 1 << "道工序。预计需要" << seconds
        << "秒,累计已用" << total << "秒。";

        COutWithMutex::Get().PrintLn(ss.str());
        /* chrono::seconds是时间长度,秒, std::this_thread只是一个namespace,
        并不是某个可以代表当前线程的对象。不过我们所需的,也只是
        在当前线程调用相关休眠函数,然后让当前线程休眠,而不是让其他线程休眠*/
        this_thread::sleep_for(chrono::seconds(seconds));

        total += seconds;
        /* 当前线程放弃执行,让操作系统调度另一线程继续执行 */
        this_thread::yield();
    }

    stringstream ss;
    ss << "[洗车房] - 完成清洗 " << desc
        << " 。累计使用 " << total << " 秒。";
    COutWithMutex::Get().PrintLn(ss.str());

    return total;
}

/* 等的就是前面“Washing()”所代表的“洗车”异步过程,
等完后取什么结果?取的就是"Washing()"的返回值,即特定洗车过程
所花费的总时长 */
//因为Washing()的返回值是int,所以shared_future的模板参数是int
void Watting(shared_future <int> f_self, shared_future <int> f_other
                        , char const* who, char const* action)
{
    bool finished_self(false), finished_other(false);
    bool lost = false;

    future_status status_self, status_other;
    for(;;)
    {
        //如果自己的车还未洗完
        if(!finished_self)
        {
            /* 不强制启动目标过程,纯粹地等待上一段时间,
            如果等的时候目标过程执行完毕,它欢快地回来告诉调用者
            “异步过程”执行完毕,可以调用get()取结果啦”,
            否则它应该是很沮丧的。 */
            status_self = f_self.wait_for(chrono::seconds(1));
            //如果status_self==ready,则finished_self为true。
            finished_self = (status_self == future_status::ready);
        }

        if(!finished_other)
        {
            status_other = f_other.wait_for(chrono::seconds(1));
            finished_other = (status_other == future_status::ready);
        }

        stringstream ss;
        ss << "[" << who << "]-";

        //如果自己洗完了,别人还没洗完
        if(finished_self && !finished_other)
        {
            //得到自己的洗车结果(用时)
            int seconds = f_self.get();

            ss << "哈哈哈!谢谢店家看得起!回头给五星好评。"
               << "这位兄弟," << seconds << " 秒洗车的境界,有空来交流。"
               << "您慢慢品茶,我有个上千万的项目要忙,告退。";

            COutWithMutex::Get().PrintLn(ss.str());
            break;
        }

        //如果都洗完了
        if(finished_self && finished_other)
        {
            int seconds = f_other.get() - f_self.get();

            if(seconds > 0)
            {
                ss << "店家,这 " << -seconds << " 秒颜面损失无价,你赔我!";
            }
            else //seconds == 0
            {
                ss << "这么巧,走了!";
            }

            COutWithMutex::Get().PrintLn(ss.str());
            break;
        }

        //自己没洗完,别人洗完了
        if(!finished_self && finished_other && !lost)
        {
            lost = true;
            int seconds = f_other.get(); //别人洗车的时间

            ss << "(" << action << ")店家你别急,豪车就需慢慢洗。"
            << " 那位兄弟,洗个车才坚持" << seconds << "秒?路上小心。";

            COutWithMutex::Get().PrintLn(ss.str());
            continue;//继续for循环
        }

        ss << "我喝口茶,再等等。";
        COutWithMutex::Get().PrintLn(ss.str());
    }
}

int main()
{
    /* 两次异步调用结果返回shared_future<T>,这样说是不准确的,
    因为asyn()函数只能返回future<T>对象,只不过它能
    进一步转换为此时我们所需要的shared_future<T>。为此,
    这里不能使用auto简化f_wash_zhang和f_wash_li的类型声明,
    倒也不是没有办法,
    可以写成 auto sf = async(...).share() //"..."是省略的入参*/

    /* 普通future就是一个收条只能用一次(钱还了,借条也请作废),
    而shared_future则是一个收条可以用多次 */
    //洗车结果,两家都关心,所以使用shared_future
    shared_future <int> f_wash_zhang =
            async(launch::async, Washing, "~张家 - 宝牛车 ~ ");

    shared_future <int> f_wash_li =
            async(launch::async, Washing, "~李家 - 倔驴车 ~");

    /* 又是一对async()调用,不过这次不存在“多处共同获取”两人等待过程的需要,
    另外也没有指定异步过程启动策略。管他两呢,爱等不等。*/
    auto f_wait_zhang = async(Watting, f_wash_zhang, f_wash_li
                , "张先生", "掏出枪形打火机点了颗烟"); //等待结果

    auto f_wait_li = async(Watting, f_wash_li, f_wash_zhang
                           , "李先生", "拿着刀伸进嘴里剔了剔牙");

    auto zero = chrono::seconds(0);
    while(f_wait_zhang.wait_for(zero) != future_status::ready
            || f_wait_li.wait_for(zero) != future_status::ready)
    {                 // wait_for()不强制启动目标过程,只是纯粹登上一段时间
        this_thread::yield(); //线程切换
//        cout << "线程yield ";
    }

    cout << "[扫地阿姨] - 两(kuai)位(dian)慢(gun)走(dan)!" << endl;

    return 0;
}
  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值