c++多线程(4): condition_variable, future, async(), promise, package_task

本文详细介绍了C++中多线程的相关概念,包括如何使用condition_variable进行条件等待,理解future、async、promise与packaged_task在异步操作中的应用,以及如何处理future的异常和限时等待。同时,还展示了并行快速排序的实现,强调了async的启动方式与package_task的区别,并提供了实例代码。
摘要由CSDN通过智能技术生成

一:使用条件变量condition_variable等待条件成立

class A
{
public:
    int i;
    A(int i) : i(i){}
};

mt19937 rnd;  //生成随机数
queue<A> q;
mutex m;
condition_variable condition;

void push_data()
{
    this_thread::sleep_for(100ms);
    int i;
    for (i = 0; i < 10; i++) //压入10条数据
    {
        A data(int(rnd()) % 1000);
        //大括号添加作用域, 使退出大括号时, lock_guard能析构
        {
            lock_guard lock1(m);
            q.push(data);
        }
        printf("push data:%d\n", data.i);
        condition.notify_one();  //当process线程在wait等待阻塞时, 唤醒甲去查验条件
    }
}

void process()
{
    while (true) //让其一直运行,
    {
        unique_lock lock1(m);

        //condition.wait(): 条件(第二个参数)成立(本例为lambda条件)则返回, 且锁住互斥, 不成立则阻塞或等待同时释放互斥
        condition.wait(lock1, []
        {
            return !q.empty();
        });
        A data = q.front();
        q.pop();

        this_thread::sleep_for(100ms);
        printf("process data:%d\n", data.i);//模拟处理数据
    }
}

int main()
{
    thread t1(process); //处理线程(消费者)
    thread t2(push_data);//生产线程
    t1.join();
    t2.join();
    return 0;
}

某次的运行结果

push data:-684
push data:302
process data:-684
process data:302
push data:-562
push data:-711
process data:-562
process data:-711
push data:204
process data:204

//此时程序还没停止, push_data线程不再压入数据, 但process线程仍在等待数据

条件变量实际上是忙等(busy-wait)的优化, 忙等就是一直循环等待条件成立, 浪费cpu资源


由于在wait的调用期间, 条件(第二个参数)可能会被多次查验, 如果产生true则立刻返回,

若此函数的调用产生副作用, 则会造成数量和频率都不确定的伪唤醒

伪唤醒: process线程获得互斥, 但却不是直接响应了push_data线程的结果

例如process线程的lamdba条件里为队列q添加数据

bool predicate()
{
    q.push(1);
    return true;
}

void process()
{
    while (true) //让其一直运行,
    {
        unique_lock lock1(m);

        //condition.wait(): 条件(第二个参数)成立(本例为lambda条件)则返回, 解锁互斥, 不成立则阻塞或等待
        //此时无法得知predicate会不会造成副作用, 
        //但实际上predicate修改了队列q并直接返回true
        condition.wait(lock1, predicate); 
        A data = q.front();
        q.pop();

        this_thread::sleep_for(100ms);
        printf("process data:%d\n", data.i);//模拟处理数据
    }
}

会一直输出1, push_data线程的数据没发挥作用

process data:1
process data:1
process data:1
process data:1

//无限重复

因此利用condition_variable时尤其要小心条件的验证不能产生副作用

当wait进入阻塞时, 才需要notify_one唤醒, 若条件直接成立, 则不会阻塞, 无须唤醒

当进入阻塞时, norify_one并不会直接唤醒,  仍需要检查条件是否成立

void process(int i)
{
    while (true) //让其一直运行,
    {
        unique_lock lock1(m);
        //此时上面push_data的唤醒不起作用,因为notify_one后还需检查条件, 此处条件不成立
        condition.wait(lock1, []{return false;});

        A data = q.front();
        q.pop();

        printf("thread:%d, process  data:%d\n", i, data.i);//模拟处理数据
        this_thread::sleep_for(100ms);
    }
}
push data:-684
push data:302
push data:-562
push data
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值