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

回调函数的实现

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

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

代码示例:

cpp 复制代码
#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主:码农论坛,该文章仅作为本人学习笔记及交流学习使用。

相关推荐
2301_80799738几秒前
代码随想录-day54
数据结构·c++·算法
CoderYanger1 分钟前
A.每日一题——2435. 矩阵中和能被 K 整除的路径
开发语言·线性代数·算法·leetcode·矩阵·深度优先·1024程序员节
我命由我123451 分钟前
微信小程序 - 页面跳转并传递参数(使用路由参数、使用全局变量、使用本地存储、使用路由参数结合本地存储)
开发语言·前端·javascript·微信小程序·小程序·前端框架·js
️公子3 分钟前
无人直播系统-黑客主题
人工智能·c#·visual studio
curry____3037 分钟前
study in pta + 豆包(求区间和)(前缀和算法)(如何处理zhan栈溢出和超出时间复杂度问题)(2025.12.2)
数据结构·c++·算法
BestOrNothing_201510 分钟前
【C++基础】Day 6:前置++ VS 后置++(语法底层 + STL规范 + 面试高频)
c++·运算符重载·面试八股·前置++·后置++·stl迭代器
●VON12 分钟前
Flutter for OpenHarmony前置知识《Flutter 路由与导航完整教程》
学习·flutter·华为·openharmony·开源鸿蒙
liliangcsdn12 分钟前
python如何写数据到docx示例
开发语言·python
缘三水13 分钟前
【C语言】10.操作符详解(下)
c语言·开发语言·c++·语法·基础定义
渡我白衣13 分钟前
深入理解算法库的灵魂——彻底掌握 <algorithm> 的范式、迭代器约束、隐藏陷阱与性能真相
数据结构·c++·人工智能·网络协议·mysql·rpc·dubbo