回调函数浅聊

1.概念:

        回调就是把一段可执行的代码像参数传递那样传递给其他的代码,而这段代码会在某个时刻被调用执行。一段代码不好传递,我们就将其封装成函数lambda表达式,类成员函数等,然后将函数的地址当作参数传递到另外一个函数,被传递的就是回调函数,被调用的时机可以是立刻,也可以是过段时间,那么这也叫做同步回调异步回调

2.函数指针:

        这个涉及到了把函数当作参数传递,这个就涉及到了函数指针,那么我们来看看什么是函数指针。

int fun(int a,int b)
{
	cout<<"hello,world"<<endl;
	return a+b;
}
int main()
{
    int (*p1)(int a,int b) = NULL;
	p1 = fun;
    cout<<p1(2,3);
}

        我们可以从这个例子总结下简单的语法格式:函数类型 (*函数名)(函数参数);

        这里的函数类型,和函数参数需要和赋值的函数保持一致。上述例子中的函数参数(int a,int b)可以选择不保留a ,b;

3.回调函数:

3.1简单回调:

        当我们了解了函数指针的使用后,我们尝试将函数指针当成一个参数传递给另外一个函数去调用它。

void callback()
{
    std::cout << "Callback function called.\n";
}
void use_callback(void (*p)())
{
    p();
}
int main()
{
    auto lambda = []()
    { std::cout << "Lambda function called.\n"; };
    void (*p)() = nullptr;
    p = callback;
    use_callback(lambda);
    use_callback(p);
    return 0;
}

上述代码中我们可以看到函数指针p被当成参数传递到了use_callback函数中去了,同样的我们也可以使用lambda表达式(本质匿名函数),函数名字(函数的地址)作为参数传递进去。下面的代码就是将函数名称作为参数传递的。

#include <iostream>
using namespace std;

void callback()
{
	std::cout<<"hello,world\n"<<endl;
}
void use_callback(void (*func)())
{
	func();
}
int main()
{
   use_callback(callback);
   return 0;
}

3.2functional简单使用:

我们可以看到,作为参数来看可调用对象是非常多的,函数名称,lambda表达式,函数指针等,我们在编写回调函数的时候是不知道会传入什么参数进来的,这样在我们试图使用统一的方式保持,或传递一个可调用对象时,会非常的繁琐。为了方便统一的管理,C++11引入了std::functional可调用对象包装器来统一的处理函数,函数对象,lambda表达式等,并允许保持和延迟执行它们。

        我们先看看functional的简单使用:

#include <functional>
void callback()
{
    std::cout << "Callback function called.\n";
}
void callback1(int a)
{
    std::cout << "Callback function called with parameter: \n" << a<<std::endl;
}
int main()
{
    std::function<void()> f = callback;
    std::function<void(int)> f1 = callback1;
    f();
    f1(3);
    return 0;
}

functional的尖括号中要保持和对应赋值函数的类型,参数一致。

        functional作为形参的使用:

#include <iostream>
#include <functional>
void callback()
{
    std::cout << "Callback function called.\n";
}
void use_callback(std::function<void()> f)
{
    f();
}
int main()
{
    auto lambda = []()
    { std::cout << "Lambda function called.\n"; };

    use_callback(callback);
    use_callback(lambda);
    return 0;
}

虽然在调用方式上没啥区别,但是多了一个统一的封装和存储管理。

3.2异步回调:

#include <iostream>
#include <thread>
#include <chrono>
#include <future>
int asynccallback(int time_s)
{
    std::cout<<"asynccallback function do some logical\n";
    std::this_thread::sleep_for(std::chrono::seconds(time_s));
    return time_s*2;
}
int main()
{
    std::promise<int> p1;
    std::future<int> f1 = std::async(std::launch::async, asynccallback, 2);
    std::thread([](std::future<int>& f, std::promise<int>& p) {
        p.set_value(f.get());
    },std::ref(f1),std::ref(p1)).detach();
    std::cout << "waiting...the result \n" <<p1.get_future().get()<< std::endl;
    return 0;
}

        上述代码就是在不同的线程之间去调用函数,涉及到了async promise,future等。这里关于异步任务的建立我们使用了async和thread两种方式,这两个方式各有千秋,具体区别如下:

        
在 C++ 中,std::thread 和 std::async 都可以用于创建并发任务,但它们之间有一些重要的区别:


调用方式:

std::thread 使用线程来执行指定的函数或可调用对象。
std::async 创建一个异步任务,通常将任务委托给线程池来执行。它返回一个 std::future 对象,允许您获取异步任务的结果。

返回值:

std::thread 不直接返回任务的结果。如果需要任务的结果,通常需要自行管理线程间通信(比如使用 std::mutex 或 std::condition_variable)。
std::async 返回一个 std::future 对象,可以用于获取异步任务的结果。

执行策略:

std::thread 允许您显式地创建一个新线程并执行指定的函数或可调用对象。
std::async 通常会根据执行策略(指定为 std::launch::async 或 std::launch::deferred)来决定是否创建新线程执行任务。

管理:

std::thread 提供了对线程的直接控制,如创建、加入、分离线程等。
std::async 通常将任务委托给线程池,隐藏了底层线程的管理。但是,具体的执行方式可能会因实现而异。

综上所述,std::thread 适合对线程进行精细控制,而 std::async 更适合用于异步任务的简单启动和结果获取
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值