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

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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

反转二叉树(力扣226)

解题思路&#xff1a;用队列进行前序遍历的同时把节点的左节点和右节点交换 具体代码如下&#xff1a; class Solution { public:TreeNode* invertTree(TreeNode* root) {if (root NULL) return root;swap(root->left, root->right); // 中invertTree(root->left)…

oracle 数据库 迁移 mysql

将 Oracle 数据库迁移到 MySQL 是一项复杂的任务&#xff0c;因为这两种数据库管理系统具有不同的架构、语法和功能。下面是一个基本的迁移步骤&#xff0c;供你参考&#xff1a; 步骤一&#xff1a;评估和准备工作 1.评估数据库结构&#xff1a;仔细分析 Oracle 数据库的结构…

让15万的车也配激光雷达,速腾发布中长距「千元机」MX

‍作者 |老缅 编辑 |德新 4月15日&#xff0c;国内头部激光雷达公司速腾聚创发布了新一代中长距激光雷达MX。 相比较其产品配置&#xff0c;最令人惊喜的是它的价格。 「MX将以低于200美元的价格作为基础&#xff0c;实现第一个项目的量产。」速腾聚创CEO邱纯潮在发布会现场…

Python连接Oracle数据库问题解决及Linux服务器操作知识

背景说明 最近在做一个视频分析的项目&#xff0c;然后需要将视频分析的数据写入到oracle数据库&#xff0c;直接在服务器上测试数据库连接的时候出现了这个bug提示&#xff0c;自己通过不断的研究探讨&#xff0c;最终把这个问题成功进行了解决&#xff0c;在这里进行一下记录…

Avi Wigderson:理论计算机科学的巨人

&#x1f3c6;个人专栏 &#x1f93a; leetcode &#x1f9d7; Leetcode Prime &#x1f3c7; Golang20天教程 &#x1f6b4;‍♂️ Java问题收集园地 &#x1f40d; Python工具 &#x1f334; 成长感悟 欢迎大家观看&#xff0c;不执着于追求顶峰&#xff0c;只享受探索过程 A…

LeetCode-热题100:98. 验证二叉搜索树

题目描述 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。 示例 1&#x…

Java项目:基于SSM框架实现的心遗非遗文创电商平台(源码+数据库)

一、项目简介 本项目是一套基于SSM框架实现的心遗非遗文创电商平台 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、…

Linux_CentOS7/8系统 - 关闭图形界面新增用户机制手册

Linux_CentOS7/8系统 - 关闭图形界面新增用户机制手册 在系统完成图形界面安装后重新启动后第一次登入&#xff0c;在图形界面会有新增用户页面&#xff0c;那如果取消关闭可以按以下操作&#xff1a; CTRLALTF2 root账号登录 yum remove gnome-initial-setup -y init 3 init …

微信小程序公共组件封装使用

1.在components目录下创建公共组件&#xff0c;以navbar为例 2.完成组件功能 3.调用&#xff0c;如果很多地方都会用到&#xff0c;建议放全局&#xff0c;如果不是则放在需要引用的文件中 3.1全局引用&#xff0c;在app.json做全局引用配置 3.2局部引用&#xff0c;在需要引入…

【C++庖丁解牛】C++11---统一的列表初始化 | auto | decltype | nullptr | STL中一些变化

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 1. C11简介2. 统一的列表…

3.1 海思SS928开发 - 烧写工具 - ToolPlatform 安装及配置

3.1 烧写工具 - ToolPlatform 安装及配置 ToolPlatform 安装 进入到开发虚拟机&#xff0c;将文件 ~/hiss928/sdk/ema_2.0.2.2/pc/ToolPlatform/ToolPlatform-1.0.11-win32-x86_64.zip 拷贝至 PC 上。PC 要求安装了 win7 及以上的操作系统。解压压缩包 ToolPlatform-1.0.11-w…

49-PCIE转网口电路设计

视频链接 PCIE转网口电路设计01_哔哩哔哩_bilibili PCIe转网口电路设计 1、PCIE转网口电路设计基本介绍 pcie转网口的设计&#xff0c;一般有intel (i350)和网讯&#xff08;wx1860&#xff09;两种方案。 2、PCIE转网口的方案 2.1、I350 2.2、WX1860 (网迅) 国产化&#…

java文件夹文件比较工具

import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.HashSet; import java.util.Set;public class FolderFileNames {public static void main(String[] args) {// 假设您要读取的文件夹路径是 &q…

强大的系统监测工具 iStat Menus for mac最新中文激活版

iStat Menus for Mac是一款功能强大的系统监控工具&#xff0c;专为Mac用户设计&#xff0c;旨在帮助用户全面了解电脑的运行状态&#xff0c;提高电脑的性能和稳定性。 iStat Menus for mac最新中文激活版下载 该软件可以实时监测CPU使用率、内存占用、网络速度、硬盘活动等各…

AGV在提高物流效率方面的优势

agv “仓库是非常讲究高科技的地方” 因为降低成本 提高效率的唯一办法 就是自动化。” 仓储作为物流整个链条的核心点&#xff0c;做好仓储的生产调节才能有效的降低整体物流成本和提升效率&#xff0c;并通过高效、安全、低成本的物流来帮助提升整体供应链效率和能力。 a…

C++异常学习

C语言传统的处理错误的方式 传统的错误处理机制&#xff1a; 终止程序&#xff0c;如assert&#xff0c;缺陷&#xff1a;用户难以接受。如发生内存错误&#xff0c;除0错误时就会终止程序。返回错误码&#xff0c;缺陷&#xff1a;需要程序员自己去查找对应的错误。如系统的…

Mac 部署 llamafile 大语言模型LLM

文章目录 Github官网本地部署 llamafile 是一种可在你自己的电脑上运行的可执行大型语言模型&#xff08;LLM&#xff09;&#xff0c;它包含了给定的开放 LLM 的权重&#xff0c;以及运行该模型所需的一切。让人惊喜的是&#xff0c;你无需进行任何安装或配置。 Github https…

scala---基础核心知识(变量定义,数据类型,流程控制,方法定义,函数定义)

一、什么是scala Scala 是一种多范式的编程语言&#xff0c;其设计初衷是要集成面向对象编程和函数式编程的各种特性。Scala运行于Java平台&#xff08;Java虚拟机&#xff09;&#xff0c;并兼容现有的Java程序。 二、为什么要学习scala 1、优雅 2、速度快 3、能融合到hado…

突破深度模型线上耗时瓶颈,我们做了什么?

广告投放是深度模型应用较为普遍的场景之一&#xff0c;虽然深度模型能够提升业务效果&#xff0c;但往往也会付出更加高额的耗时开销。滴滴现今 DSP&#xff08;Demand-Side Platform&#xff09; 业务场景中&#xff0c;耗时问题已然成为限制模型发挥的魔咒&#xff0c;为了打…

选课成绩管理系统

文章目录 员工管理系统一、项目演示二、项目介绍三、系统部分功能截图四、部分代码展示五、底部获取项目&#xff08;9.9&#xffe5;&#xff09; 员工管理系统 一、项目演示 课程管理系统 二、项目介绍 基于springbootvue的前后端分离选课成绩管理系统 该系统可做课程管理…