C++异步回调示例:多线程执行任务,主线程通过回调监测任务状态

news2024/9/20 3:20:11

1、回调函数

  回调函数定义:把函数的指针或者地址作为参数传递给另一个参数,当这个指针被用来调用其所指向的函数时,那么这就是一个回调的过程,这个被回调的函数就是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或者条件发生时由另外的一方调用的,用于对该事件或者条件进行响应,是在两个独立函数或者独立类通信的通道。

回调机制原理如下:

  1. 调用者不知道具体事件发生时需要调用的具体函数
  2. 被调函数不知道何时被调用,只知道需要完成的任务
  3. 当具体事件发生时,调用者通过函数指针来调用具体函数
  4. 回调机制中的调用者和被调函数互不依赖。

2、回调函数和普通函数的区别

   普通函数的调用过程如下:
1)主程序运行,遇到普通函数的调用后,进入被调用函数体内执行内容。
2)等待被调用函数执行完毕后,主程序继续往下执行。
3)从主程序的角度看,这个过程为“调用–>等待被调用函数执行完毕–>继续执行”。

   回调函数的调用过程如下:
1)主程序运行,遇到回调函数的调用后,发起调用;
2)主程序不等回调函数执行完毕,而是立即返回并继续往下执行。
3)调用程序执和被调用函数同时在执行。当被调函数执行完毕后,被调函数会反过来调用某个事先指定函数,以通知主程序;
这个过程称为回调(Callback),这正是回调函数名称的由来。

3、同步回调和异步回调

   回调函数分为同步回调和异步回调。同步回调可以是单线程也可以是多线程,如果多线程同步回调的话,主线程需要等待子线程回调完成后再继续执行。而异步回调必须是多线程或多进程(每个进程可以是单线程),异步回调必须依靠多线程或多进程才能完成。

(1) 同步回调:把函数b传递给函数a。执行a的时候,回调了b,a要一直等到b执行完才能继续执行;

(2) 异步回调:把函数b传递给函数。执行a的时候,回调了b,然后a就继续往后执行,b独自执行。

4、异步回调示例

4.1 示例说明

  下面我们来编写一个工作中常见的异步回调函数使用案例。案例说明:主线程发起任务,创建子线程来进行任务处理,同时主线程通过回调函数来检测任务进度状态,以便确认任务是否执行完成。

案例详情如图所示:

1)主线程传入任务参数;
2)创建子线程并传入参数;
3)主线程结束;
4)子线程启动开始工作;
5)通过回调函数监测任务执行状态。

在这里插入图片描述

4.2 示例源码

main.cpp

// main.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。

#include "workThread.h"

#include <iostream>
using namespace std;

// 回调函数监测状态
bool OnStatusChangeCallBack(workParam& stuParam)
{
	if (stuParam.nStatus == -1)
	{
		printf("Status: waiting! sInput: %s, sOutput: %s! \n", stuParam.sInput.c_str(), stuParam.sOutput.c_str());
	}
	else if(stuParam.nStatus == 0)
	{
		printf("Status: begin! sInput: %s, sOutput: %s! \n", stuParam.sInput.c_str(), stuParam.sOutput.c_str());
	}
	else if (stuParam.nStatus == 1)
	{
		printf("Status: midding! sInput: %s, sOutput: %s! \n", stuParam.sInput.c_str(), stuParam.sOutput.c_str());
	}
	else if (stuParam.nStatus == 2)
	{
		printf("Status: finish! sInput: %s, sOutput: %s! \n", stuParam.sInput.c_str(), stuParam.sOutput.c_str());
	}
	
	return true;
}

int main(int argc, char* args[])
{
	printf("The mainThread input workParam! \n");

	// 设定参数
	workParam stuParam;
	stuParam.nStatus = -1;
	stuParam.sInput = "myWorkdir";
	stuParam.sOutput = "xxx";

	printf("The mainThread create childThread! \n");

	// 创建子线程
	workThread myWork;
	myWork.setParam(stuParam);
	myWork.GetCallbackData(OnStatusChangeCallBack);

	printf("The mainThread is over! \n\n");

	return 0;
}

workThread.h

#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <thread>

struct workParam
{
	workParam()
	{
		nStatus = -1;
		sInput = "";
		sOutput = "";
	}

	workParam& operator = (const workParam& src)
	{
		nStatus = src.nStatus;
		sInput = src.sInput;
		sOutput = src.sOutput;

		return* this;
	}

	int nStatus;
	std::string sInput;
	std::string sOutput;
};

typedef bool(*CallFun)(workParam& stuParam);

class workThread
{
public:
	workThread();
	~workThread();
	void Realese();
	void setParam(const workParam& stuParam);
	void Run();
	CallFun m_callFun;
	void GetCallbackData(CallFun call_fun);
private:
	std::thread m_workThread;
	workParam m_stuParam;
};

workThread.cpp

#include "workThread.h"
#include <functional>
#include <windows.h>
using namespace std;

workThread::workThread()
{
}

workThread::~workThread()
{
	Realese();
}


void workThread::Realese()
{
	m_workThread = std::thread(std::bind(&workThread::Run, this));
	if (m_workThread.joinable())
	{
		m_workThread.join();
	}
}

void workThread::setParam(const workParam& stuParam)
{
	m_stuParam = stuParam;
}

void workThread::Run()
{
	printf("The childThread is working! \n");

	{
		m_stuParam.nStatus = 0;
		m_callFun(m_stuParam);
	}

	for (int i = 0; i < 100; i++)
	{
		if (i == 50)
		{
			Sleep(1000);
			{
				m_stuParam.nStatus = 1;
				m_stuParam.sOutput = "D";
				m_callFun(m_stuParam);
			}
		}

		if (i == 99)
		{
			Sleep(1000);
			{
				m_stuParam.nStatus = 2;
				m_stuParam.sOutput = "FF";
				m_callFun(m_stuParam);
			}
		}
	}
}

void workThread::GetCallbackData(CallFun call_fun)
{
	m_callFun = call_fun;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1612726.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何应对MySQL单表数据量过大:垂直分表与水平分表策略解析二

http://t.csdnimg.cn/AtW6Q 第三种办法&#xff1a; 同时结合ID取模分表和ID范围分表的方案&#xff0c;我们可以先用ID范围去分表&#xff0c;然后在某个ID范围内引入取模的功能。比如以前0到500万是user_0表&#xff0c;现在可以在这个范围里再分成多个表&#xff0c;比如引…

前端常用的数据加密方式

前端开发中&#xff0c;数据安全是至关重要的一个方面。数据加密是保护用户隐私和信息安全的关键方法之一。 前端常用的数据加密方式涵盖了对传输数据的加密、存储数据的加密以及客户端与服务器端之间通信的加密。 1. 对称加密算法 对称加密算法使用相同的密钥进行加密和解密…

存储过程的查询

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 在实际使用中&#xff0c;经常会需要查询数据库中已有的存储过程或者某一个存储过程的内容&#xff0c; 下面就介绍-下如何查询存储过程。 这需要使用到数据字典 user_sou…

Jupyter Notebook更改默认打开的浏览器和工作目录

Jupyter Notebook更改工作目录 打开cmd&#xff0c;输入&#xff1a;jupyter notebook --generate-config&#xff0c;可以得到Jupyter Notebook配置文件的路径&#xff0c;找到路径下的jupyter_notebook_config.py文件&#xff0c;用记事本或者Sublime打开文件 找到&#xff…

[阅读笔记25][WebArena]A Realistic Web Environment for Building Autonomous Agents

这篇论文提出了WebArena这个环境与测试基准&#xff0c;在24年1月发表。 之前的agent都是在一些简化过的合成环境中测试的&#xff0c;这会导致与现实场景脱节。这篇论文构建了一个高度逼真、可复现的环境。该环境涉及四个领域&#xff1a;电子商务、论坛讨论、软件开发和内容管…

SpringBoot 集成Nacos注册中心和配置中心-支持自动刷新配置

SpringBoot 集成Nacos注册中心和配置中心-支持自动刷新配置 本文介绍SpringBoot项目集成Nacos注册中心和配置中心的步骤&#xff0c;供各位参考使用 1、配置pom.xml 文件 在pom.xml文件中定义如下配置和引用依赖&#xff0c;如下所示&#xff1a; <properties><pr…

YOLOv9改进策略 | SPPF篇 | 利用RT-DETR的AIFI模块替换SPPFELAN助力小目标检测涨点

一、本文介绍 本文给大家带来是用最新的RT-DETR模型中的AIFI模块来替换YOLOv9中的SPPFELAN。RT-DETR号称是打败YOLO的检测模型&#xff0c;其作为一种基于Transformer的检测方法&#xff0c;相较于传统的基于卷积的检测方法&#xff0c;提供了更为全面和深入的特征理解&#x…

FairAdaBN论文速读

FairAdaBN: Mitigating Unfairness with Adaptive Batch Normalization and Its Application to Dermatological Disease Classification 摘要 深度学习在医疗研究和应用中变得越来越普遍&#xff0c;同时涉及敏感信息和关键诊断决策。研究人员观察到不同人口统计属性子组之间…

scratch图章画图 2024年3月中国电子学会图形化编程 少儿编程 scratch编程等级考试四级真题和答案解析

目录 scratch图章画图 一、题目要求 1、准备工作 2、功能实现 二、案例分析 1、角色分析 2、背景分析 3、前期准备 三、解题思路 1、思路分析 2、详细过程 四、程序编写 五、考点分析 六、推荐资料 1、入门基础 2、蓝桥杯比赛 3、考级资料 4、视频课程 5、p…

STM32应用开发——BH1750光照传感器详解

STM32应用开发——BH1750光照传感器详解 目录 STM32应用开发——BH1750光照传感器详解前言1 硬件介绍1.1 BH1750简介1.2 硬件接线 2 软件编程2.1 软件原理2.1.1 IIC设备地址2.1.2 IIC读写2.1.3 BH1750指令集2.1.4 BH1750工作流程2.1.5 BH1750测量模式 2.2 测试代码2.3 运行测试…

2024年腾讯云免费服务器最新申请入口链接

腾讯云免费服务器申请入口 txybk.com/go/free 免费服务器可选轻量应用服务器和云服务器CVM&#xff0c;轻量配置可选2核2G3M、2核8G7M和4核8G12M&#xff0c;CVM云服务器可选2核2G3M和2核4G3M配置&#xff0c;腾讯云百科txybk.com分享2024年最新腾讯云免费服务器申请入口、限制…

基于SpringBoot + Vue实现的时装购物管理系统设计与实现+毕业论文+开题报告+答辩PPT

介绍 系统包含用户、管理员两个角色 管理员&#xff1a;首页、个人中心、用户管理、商品分类管理、颜色管理、商品信息管理、商品评价管理、系统管理、订单管理 用户:首页、个人中心、商品评价管理、我的收藏管理、订单管理 前台首页:首页、商品信息、商品资讯、个人中心、后台…

Android Studio实现页面跳转

建立文件 temp.xml <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"…

Python | Leetcode Python题解之第31题下一个排列

题目&#xff1a; 题解&#xff1a; class Solution:def nextPermutation(self, nums: List[int]) -> None:i len(nums) - 2while i > 0 and nums[i] > nums[i 1]:i - 1if i > 0:j len(nums) - 1while j > 0 and nums[i] > nums[j]:j - 1nums[i], nums[j…

SPI接口的74HC595驱动数码管实现

摸鱼记录 Day_17 (((^-^))) review 前边已经学习了&#xff1a; 数码管显示原理&#xff1a;数码管动态扫描显示-CSDN博客 且挖了个SPI的坑坑 1. 今日份摸鱼任务 学习循环移位寄存器18 串行移位寄存器原理详解_哔哩哔哩_bilibili 学习SPI接口的74HC595驱动数码管19 SPI…

【编程Tool】VS code安装与使用配置保姆级教程

目录 1.软件介绍 2.软件下载&#xff1a; 3.安装 3.1. 双击可执行文件 3.2. 同意协议 3.3. 选择安装路径&#xff0c;默认在C盘 3.4. 点击下一步 3.5. 可选择所有附加任务 3.6. 点击安装 3.7. 等待安装 3.8. 点击完成 3.9. 安装成功 4.下载MinGW64 4.1. MinGW-64下载地址 &…

电脑缺失d3dcompiler_43.dll如何修复?多种修复dll问题的有效方法分享

当用户尝试在个人计算机上运行特定的软件游戏时&#xff0c;系统弹出了一条错误提示信息&#xff0c;明确指出“d3dcompiler_43.dll”文件缺失。这个动态链接库文件(dll)是Direct3D编译器的重要组成部分&#xff0c;对于许多基于Windows操作系统的应用程序&#xff0c;尤其是那…

LeetCode 热题 100 题解:普通数组部分

文章目录 题目一&#xff1a;最大子数组和&#xff08;No. 53&#xff09;题解 题目二&#xff1a;合并区间&#xff08;No. 56&#xff09;题解 题目三&#xff1a;轮转数组&#xff08;No. 189&#xff09;题解 题目四&#xff1a;除自身以外数组的乘积&#xff08;No. 238&a…

从例题出发,提高离散数学兴趣(一)集合关系

关系的性质&#xff1a;(反)自反性&#xff0c;&#xff08;反&#xff09;对称性&#xff0c;可传递性&#xff01; 例题一&#xff1a; 复合关系与逆关系&#xff1a; 例题二&#xff1a; 覆盖与划分与等价关系&#xff1a; 重要的证明&#xff1a; 偏序关系&#xff08;自反…

【高阶数据结构】并查集 -- 详解

一、并查集的原理 1、并查集的本质和概念 &#xff08;1&#xff09;本质 并查集的本质&#xff1a;森林。 &#xff08;2&#xff09;概念 在一些应用问题中&#xff0c;需要将 n 个不同的元素划分成一些不相交的集合。 开始时&#xff0c;每个元素自成一个单元素集合&…