Modern C++ 一个例子学习条件变量

这篇具有很好参考价值的文章主要介绍了Modern C++ 一个例子学习条件变量。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

问题程序

施魔法让BUG浮出水面

条件变量注意事项

修改程序


问题程序

今天无意中看到一篇帖子,关于条件变量的,不过仔细看看发现它并达不到原本的目的。

程序如下,读者可以先想想他的本意,以及有没有问题:

#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <unistd.h>
using namespace std;
//全局条件变量
condition_variable cond;
mutex _mutex;
int count = 0;
 
void fun1(){
    while(1)
    {
        count++;
        unique_lock<mutex>lock(_mutex);
        if(count%5 == 0)
        {
            cond.notify_one();
        }
        else
        {
            cout<<"this is fun1,count="<<count<<endl;
        }
        lock.unlock();
        sleep(1);
    }
}
 
void fun2()
{
    while(1)
    {
        unique_lock<mutex>lock(_mutex);
        cond.wait(lock);
        cout<<"this is fun2,count="<<count<<endl;
        lock.unlock();
        sleep(2);
    }
}
 
int main()
{
    thread t1(fun1);
    thread t2(fun2);
    t1.join();
    t2.join();
    return 0;
}

OK,本意显然是:

  1. 从1开始打印整数
  2. 线程t1, 打印非5的倍数
  3. 线程t2, 打印5的倍数

编译执行,运行的还不错,符合预期,但这都是sleep的功劳。

施魔法让BUG浮出水面

把fun1中的sleep去掉,fun2中的sleep放到cond.wait(lock)后,它BUG的面目就暴露出来了:

void fun1(){
    while(1)
    {
        count++;
        unique_lock<mutex>lock(_mutex);
        if(count%5 == 0)
        {
            cond.notify_one();
        }
        else
        {
            cout<<"this is fun1,count="<<count<<endl;
        }
        lock.unlock();
    }
}

void fun2()
{
    while(1)
    {
        unique_lock<mutex>lock(_mutex);
        cond.wait(lock);
        sleep(2);
        cout<<"this is fun2,count="<<count<<endl;
        lock.unlock();
    }
}
[mzhai@lock]$ ./a.out
this is fun1,count=1
this is fun1,count=2
this is fun1,count=3
this is fun1,count=4
this is fun2,count=6
this is fun1,count=6
this is fun1,count=7
this is fun1,count=8
this is fun1,count=9
this is fun1,count=11
this is fun1,count=12
this is fun1,count=13
this is fun1,count=14
this is fun1,count=16
this is fun1,count=17
this is fun1,count=18
this is fun1,count=19
this is fun1,count=21

多线程结果不能因随机加了几个sleep就不同,加sleep仅仅是模拟线程调度不大一样了。

再回过头来看看代码哪些地方有问题:

  1. cond.notify_one(); count是5的倍数时,t1会通过notify_one通知t2做事,但并不会阻止t1继续执行。想想一下如果t1执行的很快而t2一直没得到调度,则t1会打印1,2,3,4,6,7,8,9,11...
  2. cond.wait(lock); 可能会假唤醒,此时t1并没有通知它。

那“this is fun2,count=6” 是怎么回事哪?不应该是5吗?一种可能性是(可以通过GDB调试来模拟):

Modern C++ 一个例子学习条件变量,modern C++,c++,modern c++,条件变量

条件变量注意事项

  1. 条件变量不擅长单打独斗,一般要和flag变量与锁同时使用。
  2. notify对方线程并不代表调度让给了对方线程。

修改程序

说了那么多,怎么改哪?

 这是一个典型的你等我我等你的例子,对于这个例子都是一方干完事情另一方才能继续,完全串休化的任务,直接写到一个线程里即可。如果说我为了练习线程同步技巧非要整两个线程,那也行,condition_variable官方文档上就有一个例子实现了main线程等待worker_thread完成任务:

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>
 
std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;
 
void worker_thread()
{
    // Wait until main() sends data
    std::unique_lock lk(m);
    cv.wait(lk, []{ return ready; });
 
    // after the wait, we own the lock.
    std::cout << "Worker thread is processing data\n";
    data += " after processing";
 
    // Send data back to main()
    processed = true;
    std::cout << "Worker thread signals data processing completed\n";
 
    // Manual unlocking is done before notifying, to avoid waking up
    // the waiting thread only to block again (see notify_one for details)
    lk.unlock();
    cv.notify_one();
}
 
int main()
{
    std::thread worker(worker_thread);
 
    data = "Example data";
    // send data to the worker thread
    {
        std::lock_guard lk(m);
        ready = true;
        std::cout << "main() signals data ready for processing\n";
    }
    cv.notify_one();
 
    // wait for the worker
    {
        std::unique_lock lk(m);
        cv.wait(lk, []{ return processed; });
    }
    std::cout << "Back in main(), data = " << data << '\n';
 
    worker.join();
}

我们依样画葫芦:

#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <unistd.h>
using namespace std;
//全局条件变量
condition_variable cond;
mutex _mutex;
bool ready = false;
bool processed = false;

int count = 0;

void fun1(){
    while(1)
    {
        count++;
        unique_lock<mutex> lock1(_mutex);
        if(count%5 == 0)
        {
            ready = true;
            processed = false;
            lock1.unlock();
            cond.notify_one();
            lock1.lock();
            cond.wait(lock1, []{ return processed; });
        }
        else
        {
            cout<<"this is fun1,count="<<count<<endl;
        }
        lock1.unlock();
    }
}

void fun2()
{
    while(1)
    {
        unique_lock<mutex> lock1(_mutex);
        cond.wait(lock1, []{ return ready; });
        cout<<"this is fun2,count="<<count<<endl;
        processed = true;
        ready = false;
        lock1.unlock();
        cond.notify_one();
    }
}

int main()
{
    thread t1(fun1);
    thread t2(fun2);
    t1.join();
    t2.join();
    return 0;
}

结果符合预期,感兴趣的读者可以到处插入sleep测试一下。

啰嗦几句多线程程序的测试

多线程程序架构设计很重要,因为它很难测试,很难穷尽负面测试用例。几种可行的测试办法:文章来源地址https://www.toymoban.com/news/detail-808539.html

  1. 随机加sleep。需要改程序。参考上面。
  2. GDB调试。模拟和正常运行不同的调度策略。参考《GDB调试技巧实战--多线程&弱鸡条件变量-CSDN博客》
  3. strace、bpftrace、bcc把快速运行的程序降慢。目的是降低一个线程的速度,另一个保持原来的速度或者也降低。原来两者都是100迈前进,那一个100另一个50会不会出问题?或者10 20哪?组合就很多了。

到了这里,关于Modern C++ 一个例子学习条件变量的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Effective Modern C++ 第七章 并发API 1

    目录 条款35:优先使用基于任务而非基于线程的程序设计 要点速记:  条款36:如果异步是必要的,则指定std::launch::async 要点速记: 参考:EffectiveModernCppChinese/src/7.TheConcurrencyAPI/Item35.md at master · CnTransGroup/EffectiveModernCppChinese (github.com) 基于任务的方法通常比基于线程的方法更

    2024年02月07日
    浏览(23)
  • USACO21FEB Modern Art 3 G

    P7414 [USACO21FEB] Modern Art 3 G 题目大意 给你一个长度为 n n n 的数组,要求你在一个全部为 0 0 0 的数组中每次将一个区间 [ i , j ] [i,j] [ i , j ] 赋为同一个值,当前的赋值可以覆盖之前的值,求最少要赋值多少次才能使这个数组与给定数组相同。 1 ≤ n ≤ 300 1leq nleq 300 1 ≤ n ≤

    2024年02月09日
    浏览(26)
  • Develop Modern WinForms Applications Using .NET 8

    Bunifu UI WinForms v7.0 streamlines professional WinForms UI development with the addition of Microsoft .NET 8 support. Bunifu UI WinForms is a user interface (UI) framework designed to streamline the development of modern and visually appealing desktop applications using Microsoft\\\'s WinForms platform. It provides a wide array of pre-built, customizable UI c

    2024年04月27日
    浏览(29)
  • Introduction to modern Cryptography 现代密码学原理与协议第二章笔记

    M表示明文空间,K表示密钥空间,C表示所有可能的密文集合 完善保密加密 的概念: 简化约定,不再特殊声明 ,除数为0无意义 完全保密加密的等价公式: 证明: 必要性证明略,此证明为条件概率的简单应用 完全不可区分性 : 完善保密加密的另一形式:  证明:   敌手不可区分性

    2024年02月03日
    浏览(30)
  • 【现代密码学】笔记6--伪随机对象的理论构造《introduction to modern cryphtography》

    主要在 哈工大密码学课程 张宇老师课件 的基础上学习记录笔记。 内容补充:骆婷老师的PPT 《introduction to modern cryphtography》–Jonathan Katz, Yehuda Lindell(现代密码学——原理与协议)中相关章节 密码学复习笔记 这个博主好有意思 初步笔记,如有错误请指正 快速补充一些密码

    2024年01月16日
    浏览(30)
  • 【现代密码学】笔记 补充7-- CCA安全与认证加密《introduction to modern cryphtography》

    主要在 哈工大密码学课程 张宇老师课件 的基础上学习记录笔记。 内容补充:骆婷老师的PPT 《introduction to modern cryphtography》–Jonathan Katz, Yehuda Lindell(现代密码学——原理与协议)中相关章节 密码学复习笔记 这个博主好有意思 初步笔记,如有错误请指正 快速补充一些密码

    2024年01月17日
    浏览(35)
  • C++多线程学习(八、条件变量:condition_variable)

    目录 condition_variable notify_one的使用 notify_all的使用 主要的3个步骤: 1.调用wait函数阻塞线程 2.unique_lock 加锁线程 3.notify_one,notify_all唤醒线程

    2024年02月13日
    浏览(42)
  • 【现代密码学】笔记3.1-3.3 --规约证明、伪随机性《introduction to modern cryphtography》

    主要在 哈工大密码学课程 张宇老师课件 的基础上学习记录笔记。 内容补充:骆婷老师的PPT 《introduction to modern cryphtography》–Jonathan Katz, Yehuda Lindell(现代密码学——原理与协议)中相关章节 密码学复习笔记 这个博主好有意思 B站视频 密码学原理《Introduction to modern Cryptog

    2024年01月20日
    浏览(34)
  • 【现代密码学】笔记4--消息认证码与抗碰撞哈希函数《introduction to modern cryphtography》

    主要在 哈工大密码学课程 张宇老师课件 的基础上学习记录笔记。 内容补充:骆婷老师的PPT 《introduction to modern cryphtography》–Jonathan Katz, Yehuda Lindell(现代密码学——原理与协议)中相关章节 密码学复习笔记 这个博主好有意思 初步笔记,如有错误请指正 快速补充一些密码

    2024年01月18日
    浏览(36)
  • 【现代密码学】笔记3.4-3.7--构造安全加密方案、CPA安全、CCA安全 《introduction to modern cryphtography》

    主要在 哈工大密码学课程 张宇老师课件 的基础上学习记录笔记。 内容补充:骆婷老师的PPT 《introduction to modern cryphtography》–Jonathan Katz, Yehuda Lindell(现代密码学——原理与协议)中相关章节 密码学复习笔记 这个博主好有意思 初步笔记,如有错误请指正 快速补充一些密码

    2024年01月24日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包