当前位置: 首页 > article >正文

C++ 包装器与绑定器的应用之回调函数的实现

回调函数的实现

在消息队列和网络库的框架中,当接收到消息(报文)时,回调用户自定义的函数对象,把消息(报文)参数传给它,由它决定如何处理。

queue参考文章:C++ queue(STL queue,队列)用法详解_queue c++ 用法-CSDN博客

代码示例:

#include <iostream>

#include <string>

#include <thread>                      // 线程类头文件。

#include <mutex>                      // 互斥锁类的头文件。

#include <deque>                      // deque容器的头文件。

#include <queue>                      // queue容器的头文件。

#include <condition_variable>  // 条件变量的头文件。

#include <functional>

using namespace std;



void show(const string& message) {  // 处理业务的普通函数

    cout << "处理数据:" << message << endl;

}



struct BB {  // 处理业务的类

    void show(const string& message) {

        cout << "处理表白数据:" << message << endl;

    }

};



class AA

{

    mutex m_mutex;                                    // 互斥锁。

    condition_variable m_cond;                  // 条件变量。

    queue<string, deque<string>> m_q;   // 缓存队列,底层容器用deque。

    function<void(const string&)> m_callback;  // 回调函数对象。

public:

    // 注册回调函数,回调函数只有一个参数(消费者接收到的数据)。

    template<typename Fn, typename ...Args>

    void callback(Fn && fn, Args&&...args) {

        m_callback = bind(forward<Fn>(fn), forward<Args>(args)..., std::placeholders::_1);  // 绑定回调函数。

    }



    void incache(int num)     // 生产数据,num指定数据的个数。

    {

        lock_guard<mutex> lock(m_mutex);   // 申请加锁。

        for (int ii = 0; ii < num; ii++)

        {

            static int bh = 1;           // 编号。

            string message = to_string(bh++) + "号";    // 拼接出一个数据。

            m_q.push(message);     // 把生产出来的数据入队。

        }

        //m_cond.notify_one();     // 唤醒一个被当前条件变量阻塞的线程。

        m_cond.notify_all();          // 唤醒全部被当前条件变量阻塞的线程。

    }



    void outcache() {    // 消费者线程任务函数。

        while (true) {

            // 把互斥锁转换成unique_lock<mutex>,并申请加锁。

            unique_lock<mutex> lock(m_mutex);



            // 1)把互斥锁解开;2)阻塞,等待被唤醒;3)给互斥锁加锁。

            m_cond.wait(lock, [this] { return !m_q.empty(); });



            // 数据元素出队。

            string message = m_q.front();  m_q.pop();

            cout << "线程:" << this_thread::get_id() << "," << message << endl;

            lock.unlock();      // 手工解锁。



            // 处理出队的数据(把数据消费掉)。

            if (m_callback) m_callback(message);  // 回调函数,把收到的数据传给它。

        }

    }

};



int main()

{

    AA aa;

    // aa.callback(show);                   // 把普通函数show()注册为回调函数。

    BB bb;

    aa.callback(&BB::show, &bb);    // 把类成员函数BB::show()注册为回调函数。



    thread t1(&AA::outcache, &aa);     // 创建消费者线程t1。

    thread t2(&AA::outcache, &aa);     // 创建消费者线程t2。

    thread t3(&AA::outcache, &aa);     // 创建消费者线程t3。



    this_thread::sleep_for(chrono::seconds(2));    // 休眠2秒。

    aa.incache(2);      // 生产2个数据。



    this_thread::sleep_for(chrono::seconds(3));    // 休眠3秒。

    aa.incache(5);      // 生产5个数据。



    t1.join();   // 回收子线程的资源。

    t2.join();

    t3.join();

}

注:此课件及源代码来自B站up主:码农论坛,该文章仅作为本人学习笔记及交流学习使用。   


http://www.kler.cn/a/520181.html

相关文章:

  • 美国主要的科技大公司及其产品介绍
  • 算子--数学与人工智能中的运算力量
  • C# 提取PDF表单数据
  • 旋转的错觉
  • Java Web-Tomcat Servlet
  • 运用python进行多任务学习过程中,手动调整权重时,如何选择项目并确定合适的权重值?
  • 【四川乡镇界面】图层shp格式arcgis数据乡镇名称和编码2020年wgs84无偏移内容测评
  • Spring Boot 支持的日志框架解析与最佳实践
  • day6手机摄影社区,可以去苹果摄影社区学习拍摄技巧
  • 力扣动态规划-10【算法学习day.104】
  • Couchbase UI: Logs
  • 蓝桥杯真题 - 三国游戏 - 题解
  • vue3中suspense的用法以及使用场景
  • Synology 群辉NAS安装(6)安装mssql
  • decison tree 决策树
  • 分公司-国内外大公司-github等开源项目推荐笔记
  • 【Postgres_Python】使用python脚本批量创建和导入多个PG数据库
  • 巴菲特购买比特币
  • SpringBoot+Electron教务管理系统 附带详细运行指导视频
  • 视频多模态模型——视频版ViT