条件变量(c++ 条件变量)

条件变量(c++ 条件变量)svg xmlns http www w3 org 2000 svg style display none svg

大家好,我是讯享网,很高兴认识大家。



 <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path> </svg> <p>首先&#xff0c;我们先来认识一下条件变量。</p> 

讯享网

条件变量是一种同步原语,通常用于在多线程编程中,使一个线程在特定条件满足之前等待,同时允许其他线程在该条件发生更改时通知等待的线程。
1. “等待”:当条件不满足时(例如,某个资源还未准备好),线程可以选择等待。调用条件变量的 方法会将线程置于阻塞状态,并释放已获取的互斥锁,让其他线程有机会修改条件。
2. “通知”:当条件发生变化时(例如,资源已经准备好),线程可以通过条件变量来通知其他等待这个条件的线程。这可以通过 (唤醒一个等待线程)或 (唤醒所有等待线程)方法实现。
3. “重检”:当被通知并从 返回时,线程应重新检查条件以确定其是否真正满足。这是因为存在所谓的“虚假唤醒”,即线程可能在条件实际满足之前被唤醒。


‌‌‌‌  例如,我们可以使用条件变量来同步一个生产者线程和一个消费者线程。生产者线程负责生成数据并将其放入缓冲区,消费者线程则从缓冲区中取出数据进行处理。用条件变量可以使消费者线程在缓冲区为空(即数据不足)时等待,而在生产者线程向缓冲区添加数据后,消费者线程会被唤醒并开始处理新数据。

‌‌‌‌  条件变量通常与互斥锁一起使用以确保线程在检查条件和决定等待之间不会被打断,即这两个操作是原子的。同时,在修改条件(比如修改共享数据)时,一般也会使用互斥锁来保证数据一致性。

  1. 条件变量的要点
    1. 检查所等待的条件:在调用 方法之前,我们通常会在一个循环中检查所等待的条件。循环的目的是防止虚假唤醒,即 由于未知原因返回但条件并未满足。
    2. 使用正确的锁:在调用 , 或 时,我们需要使用一个 unique_lock 来保护条件变量。在调用 时,锁会被释放,使其他线程有机会修改条件。等 返回时,锁会被重新获得。
    3. 避免死锁:在使用条件变量时,我们需要留意不要引入死锁。例如,如果两个线程都在等待对方发送信号,但它们都无法发送信号(例如,因为它们都在等待对方释放某个资源),那么就会发生死锁。
    4. 避免滞后唤醒:如果 先于 发生,则该信号会丢失。为了防止这种情况,我们可以在修改条件的同时调用 或 。这样,如果有其他线程正在等待,它们将立即被唤醒。如果没有线程正在等待,那么这个通知将被忽视。
    5. 注意 和 的区别: 会唤醒所有等待的线程,而 只唤醒一个。如果多个线程都在等待同一个条件,那么 可能更合适。

这里我们就以消费者和生产者为例,进行代码上的深入讲解。

对于一般的生产者-消费者模型,生产者会产生数据供消费者使用。生产者需要在准备好数据的时候通知消费者,消费者通过判断是否已经有数据来决定要不要消费数据。


讯享网

生产者和消费者的实现如下所示:

讯享网

的作用是创建一个互斥锁的锁对象 lk,并在创建时自动锁定 mtx。这意味着在 lk 的作用域内,互斥锁 mtx 被锁定,确保同一时刻只有一个线程可以访问被保护的资源(如 buffer)。

有两个好处:

  1. 自动解锁:

    std::unique_lock 是一个 RAII(Resource Acquisition Is Initialization)类,意味着它会在作用域结束时自动释放锁。当 lk 超出其作用域时(如函数结束或块结束),lk 的析构函数会被调用,从而自动解锁 mtx。

  2. 避免手动解锁:

    这种设计避免了手动解锁可能带来的错误,比如忘记解锁或在解锁后再次访问共享资源。使用 std::unique_lock 可以使代码更加安全和易于维护。

这种写法可以正常工作,但是存在一个问题:每次consumer线程都会循环判断数据是否准备好,这个过程中线程不会让出资源,因此循环判断会带来不必要的开销。正因如此,才需要学习条件变量。

 

父女水果问题

问题描述:
  父亲、母亲分别向一个果盘中放置一个水果。父亲放置苹果,母亲放置橘子。儿子专门等待果盘中的苹果。女儿专门等待果盘中的橘子。当果盘中准备好水果以后,儿子和女儿分别根据自己的需要拿走水果。
  这其实也是一个生产者和消费者的模型,使用条件变量实现如下:

讯享网

在这个代码中,因为每个线程中我们都设置了sleep,所以看起来他可能是按父亲-儿子-母亲-女儿这样的顺序进行的。如果将sleep删去的话,那其实在盘子为空的时候,父亲进程和母亲进程是有相同的概率实现的。


小讯
上一篇 2025-06-01 17:01
下一篇 2025-05-25 21:40

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/175483.html