C/C++ 回调函数 callback 异步编程

一、C语言的回调函数

1.小试牛刀 

#include <iostream>
using namespace std;
#include <memory>
#include <stdlib.h>int add(int a, int b) {return a + b;
}void test01() {// 函数指针可以指向任何类型的函数,只要函数的参数列表和返回值类型匹配即可int (*pFunc)(int,int) = add;// 函数指针可以像普通函数一样被调用,通过函数指针变量名加上括号的方式int result = (*pFunc)(1,2);cout << result << endl; // 输出 3
}// typedef 返回类型(*新的函数名)(参数列表)
typedef int (*INT_func)(int,int);
void test02() {INT_func pFunc = add;int result = pFunc(2,3);cout << result << endl; // 输出 5
}// 回调函数,它允许一个函数作为参数传递给另一个函数
// 这种特性使得我们可以将一些特定的任务委托给其他函数来完成// 定义一个函数指针类型
typedef void(*Callback)(int);
// 定义一个函数,该函数接受一个回调函数作为参数
void doSomething(Callback callback) {cout<<"Doing something..."<<endl;// 调用回调函数int data = 1024;callback(data);
}// 定义一个回调函数
void printMyData(int data) {cout<<"My data is: "<<data<<endl;
}int main() {test01();test02();// 将回调函数传递给doSomething函数/*doSomething函数接受一个Callback类型的参数,这是一个指向函数的指针.doSomethings函数调用这个回调函数,并且将一个整型变量作为参数传递给它printMyData在此是一个简单的回调函数,它接受一个整型变量作为参数并且把它打印出来*/doSomething(printMyData);return 0;
}
  • 打印结果:
PS D:\Work\c++> ./bin/app     
3
5
Doing something...
My data is: 1024
PS D:\Work\c++>

2.动态函数指针 

在学习这个知识点的时候,我遇到的坑,非常感谢这位大佬给我指点迷津:

动态函数指针free报错_编程语言-CSDN问答icon-default.png?t=N7T8https://ask.csdn.net/questions/8061857?spm=1001.2014.3001.5505

  • micthis大佬写的代码
#include <iostream>
using namespace std;
#include <memory>
#include <stdlib.h>
int add(int a, int b) {return a + b;
}
/*动态函数指针是指在运行时根据需要动态分配和修改的函数指针它可以在程序运行时根据需要指向不同的函数,从而实现更加灵活和动态的函数调用在c++中,可以使用动态内存分配函数(如malloc或new)来创建动态函数指针
*/
int test01() {// 创建一个指向函数的指针int(**pFunc)(int, int);// 使用malloc动态分配内存int size = sizeof(int(*)(int, int));pFunc = (int(**)(int, int))malloc(size);// 将函数指针指向 add函数*pFunc = add;// 调用函数int result = (*pFunc)(2, 3);cout << result << endl; // 输出 5// 释放内存free(pFunc);return 0;
}
int main() {test01();return 0;
}

打印结果: 

PS D:\Work\c++> ./bin/app
5
PS D:\Work\c++>

3.异步编程

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>// A的实现,一般会隐藏
typedef void (*CallbackPtr)(int);// 函数指针定义typedef struct dataCB{int data;CallbackPtr callback;
}dataCB;// 创建实例
dataCB dataCBInstance = {0, NULL};void* callback_thread(void* arg) { // 此处用的是一个线程// 循环改变p->a的值为 0 1 2 3 4 5 6 7 8 9,每个3s改变一次dataCB* p = (dataCB*)arg;while (1) {sleep(3);// 延时3s执行callback函数p->callback(p->data);// 函数指针执行函数,这个函数来自于应用层Bp->data = (p->data + 1) % 10;}
}void startup_app_A() {// 创建线程pthread_t tid;pthread_create(&tid, NULL, callback_thread, (void*)&dataCBInstance);   
}// 给B的接口,接收注册函数
extern void SetCallBackFun(CallbackPtr cb) {printf("SetCallBackFun print! \n");dataCBInstance.callback = cb;
}// //-----------------------应用者B-------------------------------
void recieve(int data)       // 应用者增加的函数,此函数会在A中被执行
{//do somethingprintf("B得到A的数据 = %d\n",data);
}int main(void) {// 启动Astartup_app_A();SetCallBackFun(recieve);// 主函数while (1) {// std::cout << "main function" << std::endl;printf("main function\n");sleep(2);}return 0;
}
PS D:\Work\c++> ./bin/app
SetCallBackFun print!
main function
main function
B得到A的数据 = 0
main function
B得到A的数据 = 1
main function
main function
B得到A的数据 = 2
main function
B得到A的数据 = 3
main function
main function
B得到A的数据 = 4
main function
B得到A的数据 = 5
main function
main function
B得到A的数据 = 6
main function
B得到A的数据 = 7
main function
main function
B得到A的数据 = 8
main function
B得到A的数据 = 9
main function
main function
B得到A的数据 = 0
main function
B得到A的数据 = 1
main function
main function
B得到A的数据 = 2
main function
B得到A的数据 = 3
main function
main function
B得到A的数据 = 4
main function
B得到A的数据 = 5
main function
main function
B得到A的数据 = 6
main function
B得到A的数据 = 7
main function
main function
B得到A的数据 = 8
main function
B得到A的数据 = 9
main function
main function
B得到A的数据 = 0
main function

参考文章:C/C++面向对象(OOP)编程-回调函数详解(回调函数、C/C++异步回调、函数指针)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_47324800/article/details/135315345

二、C++回调函数

1.动态函数指针

#include <iostream>
using namespace std;
#include <memory>
#include <stdlib.h>
int add(int a, int b) {return a + b;
}
/*动态函数指针是指在运行时根据需要动态分配和修改的函数指针它可以在程序运行时根据需要指向不同的函数,从而实现更加灵活和动态的函数调用在c++中,可以使用动态内存分配函数(如malloc或new)来创建动态函数指针
*/
typedef int(*handleFunc)(int,int);
int test01() {// 创建一个指向函数的指针int(**pFunc)(int, int);pFunc = new handleFunc;// 将函数指针指向 add函数*pFunc = add;// 调用函数int result = (*pFunc)(2, 3);cout << result << endl; // 输出 5// 释放内存delete pFunc;pFunc = nullptr;return 0;
}
int main() {test01();return 0;
}

  2.简单回调

#include <iostream>
#include <functional>// 定义一个回调函数类型
typedef std::function<void(int)> Callback;// 定义一个接受回调函数的函数
void process(int value,Callback callback) {std::cout<<"传入处理值: "<<value<<std::endl;callback(value); // 调用回调函数
}// 定义一个回调函数
int add(int value) {value += 10;std::cout<<"传出结果值: "<<value<<std::endl;return value;
}int main() {int value = 42;process(value,add); // 传递回调函数给process函数return 0;
}

执行结果:

PS D:\Work\c++> ./bin/app
传入处理值: 42
传出结果值: 52
PS D:\Work\c++> 

 3.使用包装器function 

参考文章:C++之可调用对象、bind绑定器和function包装器_完整实现bind和function代码c++-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_65743593/article/details/128963676

 (1) 可调用对象

// 可调用对象
/*在C++中,可以像函数一样的调用的有:普通函数,类的静态成员函数、仿函数、lambda函数,类的非静态成员函数、可被转换为函数的类的对象,统称可调用对象或函数对象可调用对象有类型,可以用指针存储它们的地址,可以被引用(类的成员函数除外)
*/#include <iostream>
using namespace std;
class Object {
public:// 仿函数void operator()(int age, string name) {cout << "年龄:" << age << ",姓名:" << name << endl;}// 类的非静态成员函数void show(int age, string name) {cout << "年龄:" << age << ",姓名:" << name << endl;}
};// 仿函数
void test01() {Object obj;obj(20, "呵呵哒");Object& objRef = obj; // 引用函数objRef(18, "小比尔");
}// lambda函数
void test02() {auto func = [](int age, string name) {cout << "年龄:" << age << ",姓名:" << name << endl;};func(20, "heheda");auto& funcRef = func;// 引用lambda对象funcRef(23, "小比尔");
}// 类的非静态成员函数有地址,但是只能通过类的对象才能调用它,
// C++对它做了特别处理,类的非静态成员函数只有指针类型,
// 没有引用类型,不能引用
void test03() {Object obj;obj.show(30, "智慧老人");void(Object:: *pobj)(int, string) = &Object::show; // 定义类的成员函数的指针(obj.*pobj)(20, "呵呵哒");using PFun = void(Object::*)(int, string);PFun pShow = &Object::show;(obj.*pShow)(78, "圣诞老人");
}int main() {test03();return 0;
}

(2)C++之可调用对象,bind绑定器和function包装器

// 包装器function
// 包含头文件:#include <functional>
// std::function<返回值类型(参数类型列表)> diy_name = 可调用对象;#include <iostream>
#include <functional>
#include <string>
using namespace std;
enum OP {ADD,MUL,SUB
};int add(int a, int b) {return a + b;
}using handleFunc = function<int(int, int)>;
class Object {
public:int add(int a, int b) {return a + b;}static int sub(int a, int b) {return a - b;}static int mul(int a, int b) {return a * b;}// 仿函数int operator()(int a, int b, handleFunc cb, OP op) {switch (op) {case ADD:cout << "("<< a << "+" << b << ") = ";break;case MUL:cout << "(" << a << "*" << b << ") = ";break;case SUB:cout << "(" << a << "-" << b << ") = ";break;}cout << cb(a, b) << endl;return cb(a, b);}
};void test01() {Object obj;function<int(int, int)> func = add;cout << func(1, 2) << endl;
}void test02() {Object obj;handleFunc addCB = std::bind(&Object::add, &obj, std::placeholders::_1, std::placeholders::_2);cout << "addCB(1, 2): " << addCB(1, 2) << endl;handleFunc subCB = Object::sub;cout << "subCB(9, 3): " << subCB(9, 3) << endl;subCB = obj.mul;cout << "subCB(10, 6): " << subCB(10, 6) << endl;handleFunc mulCB = Object::mul;cout << "mulCB(3, 3): " << subCB(3, 3) << endl;subCB = obj.mul;cout << "mulCB(2, 6): " << subCB(2, 6) << endl;function<int(int, int, handleFunc, OP)> operCB = obj;operCB(2, 3, add, ADD);operCB(4, 1, obj.sub, SUB);operCB(2, 9, obj.mul, MUL);
}int main() {//test01();test02();return 0;
}

#include <iostream>
#include <functional>
using namespace std;
using handleFunc = function<void()>;
class Object {
public:// 构造函数参数是一个包装器对象Object(const handleFunc& f) :m_callback(f) {}void notify() {m_callback();// 调用通过构造函数得到的函数指针}
private:handleFunc m_callback;
};class Subject{
public:void operator()() { cout << "heheda" << endl; }
};int main() {Subject s;Object obj(s);obj.notify();return 0;
}

#include <iostream>
#include <functional>
using namespace std;
class Person {
public:// 仿函数void operator()(int age, string name) {cout << "age: " << age << ",name: " << name << endl;}void show(int age, string name) {cout << "age: " << age << ",name: " << name << endl;}
};void test01() {Person person;// 仿函数function<void(int, string)> opFunc = bind(Person(), placeholders::_1, placeholders::_2);opFunc(20,"heheda");// 类成员函数需要绑定该类的this指针 Person p1;function<void(Person&, int, string)> showFunc = bind(&Person::show,placeholders::_1, placeholders::_2, placeholders::_3);showFunc(p1, 17, "Tom");// 为了统一,将对象提前绑定function<void(int, string)> showFunc2 =bind(&Person::show, p1, placeholders::_1, placeholders::_2);showFunc2(8, "Jerry");
}int main() {test01();
}

#include <iostream>
#include <functional>
#include <thread>
#include <unistd.h>
using namespace std;// A的实现,一般会隐藏
using CallbackPtr = std::function<void(int)>;typedef struct dataCB{int data;CallbackPtr callback;
}dataCB;// 创建实例
dataCB dataCBInstance = {0, NULL};void* callback_thread(void* arg) { // 此处用的是一个线程// 循环改变p->a的值为 0 1 2 3 4 5 6 7 8 9,每个3s改变一次dataCB* p = (dataCB*)arg;while (1) {sleep(3);// 延时3s执行callback函数p->callback(p->data);// 函数指针执行函数,这个函数来自于应用层Bp->data = (p->data + 1) % 10;}
}void startup_app_A() {// 创建线程std::thread(callback_thread, (void*)&dataCBInstance).detach(); // .detach()分离线程
}// 给B的接口,接收注册函数
extern void SetCallBackFun(CallbackPtr cb) {printf("SetCallBackFun print! \n");dataCBInstance.callback = cb;
}// //-----------------------应用者B-------------------------------
void recieve(int data)       // 应用者增加的函数,此函数会在A中被执行
{//do somethingprintf("B得到A的数据 = %d\n",data);
}int main(void) {// 启动Astartup_app_A();SetCallBackFun(recieve);// 主函数while (1) {printf("main function\n");sleep(2);}return 0;
}

(3)异步编程

#include <iostream>
#include <functional>
#include <thread>
#include <unistd.h>
using namespace std;// A的实现,一般会隐藏
using CallbackPtr = std::function<void(int)>;typedef struct dataCB{int data;CallbackPtr callback;
}dataCB;// 创建实例
dataCB dataCBInstance = {0, NULL};void* callback_thread(void* arg) { // 此处用的是一个线程// 循环改变p->a的值为 0 1 2 3 4 5 6 7 8 9,每个3s改变一次dataCB* p = (dataCB*)arg;while (1) {sleep(3);// 延时3s执行callback函数p->callback(p->data);// 函数指针执行函数,这个函数来自于应用层Bp->data = (p->data + 1) % 10;}
}void startup_app_A() {// 创建线程std::thread(callback_thread, (void*)&dataCBInstance).detach(); // .detach()分离线程
}// 给B的接口,接收注册函数
extern void SetCallBackFun(CallbackPtr cb) {printf("SetCallBackFun print! \n");dataCBInstance.callback = cb;
}// //-----------------------应用者B-------------------------------
void recieve(int data)       // 应用者增加的函数,此函数会在A中被执行
{//do somethingprintf("B得到A的数据 = %d\n",data);
}int main(void) {// 启动Astartup_app_A();SetCallBackFun(recieve);// 主函数while (1) {printf("main function\n");sleep(2);}return 0;
}
PS D:\Work\c++> ./bin/app
SetCallBackFun print! 
main function
main function
B得到A的数据 = 0
main function
main function
B得到A的数据 = 1
main function
B得到A的数据 = 2
main function
main function
B得到A的数据 = 3
main function
B得到A的数据 = 4
main function
main function
B得到A的数据 = 5
main function
B得到A的数据 = 6
main function
B得到A的数据 = 7
main function
main function
B得到A的数据 = 8
main function
B得到A的数据 = 9
main function
PS D:\Work\c++> cmake --build build
[100%] Built target app
PS D:\Work\c++> ./bin/app
SetCallBackFun print! 
main function
main function
B得到A的数据 = 0
main function
B得到A的数据 = 1
main function
main function
B得到A的数据 = 2
main function
B得到A的数据 = 3
main function
main function
B得到A的数据 = 4
main function
main function
B得到A的数据 = 5
main function
B得到A的数据 = 6
main function
main function
B得到A的数据 = 7
main function
B得到A的数据 = 8
main function
main function
B得到A的数据 = 9
main function
B得到A的数据 = 0
main function
main function
B得到A的数据 = 1
main function
B得到A的数据 = 2
main function
B得到A的数据 = 3
main function
main function
B得到A的数据 = 4
main function
B得到A的数据 = 5
main function
main function
B得到A的数据 = 6
main function
B得到A的数据 = 7
main function
main function
B得到A的数据 = 8
main function
B得到A的数据 = 9
main function
main function
B得到A的数据 = 0
main function
B得到A的数据 = 1
main function
main function
B得到A的数据 = 2
main function
B得到A的数据 = 3
main function
main function
B得到A的数据 = 4
main function
B得到A的数据 = 5
main function
main function
B得到A的数据 = 6
main function
B得到A的数据 = 7
main function
main function
B得到A的数据 = 8
main function
B得到A的数据 = 9
main function
main function
B得到A的数据 = 0
main function
B得到A的数据 = 1
main function
main function
B得到A的数据 = 2
main function
B得到A的数据 = 3
main function
main function
B得到A的数据 = 4
main function
B得到A的数据 = 5
main function
main function
B得到A的数据 = 6
main function
B得到A的数据 = 7
main function
main function
B得到A的数据 = 8
main function
B得到A的数据 = 9
main function
main function
B得到A的数据 = 0
main function
B得到A的数据 = 1
main function
main function
B得到A的数据 = 2
main function
B得到A的数据 = 3
main function
main function
B得到A的数据 = 4
main function
B得到A的数据 = 5
main function
main function
B得到A的数据 = 6
main function
B得到A的数据 = 7
main function
main function
B得到A的数据 = 8
main function
B得到A的数据 = 9
main function
main function
B得到A的数据 = 0
main function
B得到A的数据 = 1
main function
main function
B得到A的数据 = 2
main function
B得到A的数据 = 3
main function
main function
B得到A的数据 = 4
main function
B得到A的数据 = 5
main function
main function
B得到A的数据 = 6
main function
B得到A的数据 = 7
main function
main function
B得到A的数据 = 8

参考文章:

c++ 用std::function包装类的非静态成员_c++ function 绑定非静态成员函数-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_62953519/article/details/128438241

未完待续 ~

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

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

相关文章

如何结合ChatGPT生成个人魔法咒语词库

3.6.1 ChatGPT辅助力AI绘画 3.6.1.1 给定主题让ChatGPT直接描述 上面给了一个简易主题演示一下&#xff0c;这是完全我没有细化的提问&#xff0c;然后把直接把这些关键词组合在一起。 关键词&#xff1a; 黄山的美景&#xff0c;生机勃勃&#xff0c;湛蓝天空&#xff0c;青…

厕所革命与可持续发展的“九牧方案”

人类文明的历史&#xff0c;就是厕所的革命史&#xff0c;小小的厕所里&#xff0c;承载着大故事。 2015 年&#xff0c;印度一个名叫娜尔的女孩&#xff0c;因为丈夫不愿意在家盖厕所&#xff0c;向法庭提出了离婚申请&#xff0c;由此引发了全印度“无厕所&#xff0c;无新娘…

OSG帧渲染,如何实现自定义动画效果

看到这个标题,老司机可能会想到OSG动画相关的内容,比如osg::AnimationPath类和osg::AnimationPathCallback类,这些动画类,可以实现按照一定的插值方式,生成路径,物体对象按照生成的路径或者预先指定的路径来完成相应的动作的动画。 路径动画有三种动画模式,分别为单摆环…

【百度Apollo】探索创新之路:深入了解Apollo开放平台

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下…

树莓派突然不能ssh远程连接的踩坑记录及解决方案

在家研究树莓派&#xff0c;远程连接树莓派吃了不少苦&#xff0c;总是一些意想不到的问题出现&#xff0c;明明昨天还能远程连接&#xff0c;今天又不能了。经过一系列排查&#xff0c;终于锁定&#xff1a; 因为我之前设置的树莓派的静态ip地址&#xff0c;但是可能因为是家…

ai创作软件有哪些?这5个软件了解一下

ai创作软件有哪些&#xff1f;随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;在各个领域都展现出了惊人的实力。特别是在内容创作领域&#xff0c;AI技术已经成为了助力创作者们提高效率、释放创意的得力助手。今天&#xff0c;我们将为大家介绍五款AI创作…

软件工程(最简式总结)

目录 第一章:概述 1.软件危机的表现原因 2.常见的软件开发方法包括&#xff1a; 3.软件工程基本原则 4.软件工程三要素 5.设计模式的分类 6.针对变换型数据流设计步骤 7.针对事务型数据流设计步骤 第二章&#xff1a;软件过程 1.软件生命周期 2.软件过程模型 &…

flask_django_python五金电商网络营销的可视化分析研究

前面部分完成了系统需求分析&#xff0c;了解到新闻数据业务方面的需求&#xff0c;系统主要分为用户管理、五金信息管理、在线留言、系统管理等功能。销的可视化研究&#xff0c;并对这些数据进行处理&#xff0c; 然后对这些数据进行可视化分析和统计。 Python 爬虫技术目前来…

js数组和字符串之间的转换方式以及数组的一些方法

一、数组和字符串之间的转换方式 1&#xff09;将字符串切割成字符串数组—stringObject.split(separator, howmany) seperator-----字符串、正则表达式&#xff0c;必需 howmany------指定返回的数组的最大长度&#xff0c;可省略&#xff0c;省略后全量返回 源代码 var str&q…

c++阶梯之类与对象(一)

目录 1.面向过程与面向对象 c语言的视角&#xff1a; c的视角 2. 类的引入 3. 类的定义 3.1 类的两种定义方式 3.2 成员变量如何命名 4. 类的访问限定符与封装 4.1 访问限定符 4.2 封装 5. 类的作用域 6. 类的实例化 7. 类对象模型 7.1 怎么计算一个类对象的…

redis布隆过滤器(Bloom)详细使用教程

文章目录 布隆过滤器1. 原理2. 结构和操作3. 特点和应用场景4. 缺点和注意事项 应用-redis插件布隆过滤器使用详细过程安装以及配置springboot项目使用redis布隆过滤器下面是布隆过滤器的一些基础命令 扩展 布隆过滤器 Bloom 过滤器是一种概率型数据结构&#xff0c;用于快速判…

CUDA/TensorRT部署知识点

CUDA相关: 1、CUDA核函数嵌套核函数的用法多吗? 答:这种用法非常少,主要是因为启动一个kernel本身就有一定延迟,会造成执行的不连续性。 2、如下代码里的 grid/block 对应硬件上的 SM 的关系是什么? 答:首先需要理解grid/block是软件层的概念,而SM是硬件层的概念。所…

springboot151基于web的人力资源管理系统的设计与实现

人力资源管理系统的设计与实现 摘 要 传统信息的管理大部分依赖于管理人员的手工登记与管理&#xff0c;然而&#xff0c;随着近些年信息技术的迅猛发展&#xff0c;让许多比较老套的信息管理模式进行了更新迭代&#xff0c;员工信息因为其管理内容繁杂&#xff0c;管理数量繁…

SSH免密切换服务器案例-ssh协议(公钥和私钥)

公钥和私钥理解 公钥提供加密&#xff0c;私钥解密&#xff0c;公钥可以共享&#xff0c;私钥不可以。举例公钥相当于锁头&#xff0c;可以给别人用&#xff0c;钥匙相当于私钥&#xff0c;只能开自己发出去的锁头&#xff0c;也就是私钥和公钥成对&#xff0c;私钥只能解密对…

~小青蛙跳台阶~C语言~刷题

引言 这次&#xff0c;我们要与一只活泼可爱的小青蛙合作&#xff0c;并引导它跳台阶。小青蛙的体力十分充沛&#xff0c;尤其喜欢跳跃&#xff0c;让它作为我们的助手&#xff0c;来看看有几种跳跃指定台阶数的方法。 本文会涉及到函数递归的知识&#xff0c;后续我会更新讲解…

清华系2B模型杀出,性能吊打LLaMA-13B

2 月 1 日&#xff0c;面壁智能与清华大学自然语言处理实验室共同开源了系列端侧语言大模型 MiniCPM&#xff0c;主体语言模型 MiniCPM-2B 仅有 24 亿&#xff08;2.4B&#xff09;的非词嵌入参数量。 在综合性榜单上与 Mistral-7B 相近&#xff0c;在中文、数学、代码能力表现…

基于深度卷积神经网络的图像配准(DeepSlice)

文章目录 一、基于DeepSlice的切片配准1.1、研究现状1.2、网络模型&#xff08;DeepSlice&#xff09;1.3、优化策略1.3.1、开发了一个基准数据集&#xff08;GT&#xff09;1.3.2、构建了阶段二的训练数据集&#xff08;增强训练&#xff09;1.3.3、角度集成 切割索引&#x…

【Linux】统信服务器操作系统V20 1060a-AMD64 Vmware安装

目录 ​编辑 一、概述 1.1 简介 1.2 产品特性 1.3 镜像下载 二、虚拟机安装 一、概述 1.1 简介 官网&#xff1a;统信软件 – 打造操作系统创新生态 统信服务器操作系统V20是统信操作系统&#xff08;UOS&#xff09;产品家族中面向服务器端运行环境的&#xff0c;是一款…

Linux驱动 SPI子系统

1、SPI协议 SPI&#xff08;Serial Peripheral Interface&#xff09;是一种同步串行数据通信协议&#xff0c;通常用于连接微控制器和外部设备&#xff0c;如传感器、存储器、显示器等。SPI协议使用四根线进行通信&#xff0c;包括时钟线&#xff08;SCLK&#xff09;、数据输…

CSS要点总结

一、CSS 快速入门 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>css 快速入门</title><!-- 解读1. 在 head 标签内&#xff0c;出现了 <style type"text/css"></style…