同步回调函数和异步回调函数

回调函数

回调函数一般是在封装接口的时候,回调显得特别重要,我们首先假设有两个程序员在写代码,A程序员写底层驱动接口,B程序员写上层应用程序,然而此时底层驱动接口A有一个数据d需要传输给B,此时有两种方式: 
1.A将数据d存储好放在接口函数中,B自己想什么时候去读就什么时候去读,这就是我们经常使用的函数调用,此时主动权是B。 
2.A实现回调机制,当数据变化的时候才将通知B,你可以来读取数据了,然后B在用户层的回调函数中读取速度d,完成OK。此时主动权是A。 
很明显第一种方法太低效了,B根本就不知道什么时候该去调用接口函数读取数据d。而第二种方式由于B的读取数据操作是依赖A的,只有A叫B读数据,那么B才能读数据。也即是实现了中断读取。 
那么回调是怎么实现的呢,其实回调函数就是一个通过函数指针调用的函数。如果用户层B把函数的指针(地址)作为参数传递给底层驱动A,当这个指针在A中被用为调用它所指向的函数时,我们就说这是回调函数。 
注意:是在A中被调用,这里看到尽管函数是在B中,但是B却不是自己调用这个函数,而是将这个函数的函数指针通过A的接口函数传自A中了,由A来操控执行,这就是回调的意义所在。

同步回调和异步回调

首先,理解几个概念:

1.回调可以是同步也可以是异步

2.同步可以是单线程也可以是多线程

异步必须是多线程或多进程(每个进程可以是单线程) ==> 换句话说,异步必须依靠多线程或多进程才能完成

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

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

直接看例子

A.h

#ifndef A_H
#define A_H

typedef void (*pcb)(int a); //函数指针定义,后面可以直接使用pcb,方便
void SetCallBackFun(int a, pcb callback);

#endif

同步回调

synA.c

#include <stdio.h>
#include "A.h"

//-----------------------底层实现A-----------------------------
//留给应用层B的接口函数
void SetCallBackFun(int a, pcb callback)
{
  printf("A:start\n");
  callback(a);
  printf("A:end\n");
}

synB.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "A.h"
//-----------------------应用者B-------------------------------

void fCallBack(int a) // 应用者增加的函数,此函数会在A中被执行
{
  //do something
  printf("B:start\n");
  printf("a = %d\n",a);
  sleep(5);
  printf("B:end\n");
}

int main(void)
{
  SetCallBackFun(4,fCallBack);
  return 0;
}

异步回调

asynA.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include "A.h"
//-----------------------底层实现A-----------------------------
typedef struct parameter{
  int a ;
  pcb callback;
}parameter;

void* callback_thread(void *p1)//此处用的是一个线程
{
  //do something
  parameter* p = (parameter*)p1 ;
  sleep(5);
  p->callback(p->a);//函数指针执行函数,这个函数来自于应用层B
}

//留给应用层B的接口函数
void SetCallBackFun(int a, pcb callback)
{
  printf("A:start\n");
  parameter *p = malloc(sizeof(parameter)) ;
  p->a = a;
  p->callback = callback;

  //创建线程
  pthread_t pid;
  pthread_create(&pid,NULL,callback_thread,(void *) p);
  printf("A:end\n");

  //阻塞,等待线程pid结束,才往下走
  pthread_join(pid,NULL);
}

asynB.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "A.h"
//-----------------------应用者B-------------------------------
void fCallBack(int a) // 应用者增加的函数,此函数会在A中被执行
{
  //do something
  printf("B:start\n");
  printf("a = %d\n",a);
  sleep(5);
  printf("B:end\n");
}

int main(void)
{
  SetCallBackFun(4,fCallBack);
  return 0;
}

运行结果比较:

同步回调 异步回调
A:start
B:start
a = 4
B:end
A:end
A:start
A:end
B:start
a = 4
B:end

由执行结果可以看出:同步回调,A需要等待B执行完成才能执行A剩余的操作;异步回调,A刚执行B,不必等待B结束,就执行A剩余的操作,之后B的操作也随之end。

原文地址:https://www.cnblogs.com/still-smile/p/12048078.html

时间: 2024-08-15 11:48:35

同步回调函数和异步回调函数的相关文章

关于异步回调的一段代码及相关总结

昨天遇到了一个问题,就是想在外部js里实现页面加载完了就执行js,类似于jquery中$或者window.onload,当然和window.onload还有所不同,因为window.onload是在图片啊其他的资源加载完了才开始执行的,而我想在尽可能快的执行,问题可以用一段代码来描叙: 1 <html> 2 <head> 3 <script src="test.js“></script> 4 5 </head> 6 <body&g

2015/01/23 – 不要对异步回调函数进行同步调用

绝对不能对异步回调函数(即使在数据已经就绪)进行同步调用. 如果对异步回调函数进行同步调用的话,处理顺序可能会与预期不符,可能带来意料之外的后果. 对异步回调函数进行同步调用,还可能导致栈溢出或异常处理错乱等问题. 如果想在将来某时刻调用异步回调函数的话,可以使用 setTimeout 等异步API. function onReady(fn) { var readyState = document.readyState; if (readyState == 'interactive' || re

同步异步 + 回调函数

重点记忆 异步回调函数 如果进程池+回调: 回调函数由主进程去执行. 如果线程池+回调: 回到函数由空闲的线程去执行.(比如有4个线程,10个任务,第一轮完成4个任务,交由主线程处理结果,第二轮同样如此,但是第三轮将会空闲出2个子进程,则这2个子进程将会和主进程一同处理结果,以此类推,当所有的任务完成时,所有的子进程和主进程一起处理结果,增加效率) 回调函数不管有没有返回数据,返回值都是None,回调函数内部加函数名是调用此函数,obj隐形传参 1.概念 1. 从执行的角度 阻塞: 程序运行时,

协程,事件,队列,同步,异步,回调函数

协程 什么是协成?单个线程并发的处理多个任务,程序控制协成的切换+保持状态,协成的切换速度非常快,蒙蔽了操作系统的眼睛,让操作系统认为CPU一直在运行 进程或线程都是由操作系统控制CPU来回切换,遇到阻塞就切换执行其他任务,协成是程序控制的,霸占CPU执行任务,会在操作系统控制CPU之前来回切换,操作系统就认为CPU一直在运作 协程的优点: 1.开销小 2.运行速度快 3.协程会长期霸占CPU只执行我程序里的所有任务 协程的缺点: 1.协程属于微并发,处理任务不易过多 2.协程的本质是单线程,无

C#的异步回调函数

关于C#的异步回调,在ActionScript 3.0当中 , 有关键字Function , 可以直接传class函数为回调函数.但是在C#当中,需要使用到委托,其中应用的最多的当属 : Action / Func .当然你可以使用关键字delegate来自定义委托.这里翼Action /  Func为例来讲解C#的异步回调,如果不了解C#的委托机制,需要自己先百度/Google一下,再来看这篇博客. BeginInvoke 方法用于启动异步调用.它与您需要异步执行的方法具有相同的参数,只不过还

WPF异步回调时回调函数如何获取异步函数产生的变量

有这么一个问题,WPF在使用异步回调的时候,回调函数需要用到异步函数里产生的一个变量,例如异步函数里查询数据库得到了一个DataTable,如何传递给回调函数呢? [方案一]使用全局变量 很容易想到的是用全局变量,这也是最简单的办法.但是如果我想循环调用呢,例如回调函数判断异步函数执行完之后的DataTable有没有数据,有数据则继续异步(BeginInvoke),这时候如果使用全局变量可能会出现意外情况,因为是循环调用,回调函数使用的DataTable是不是你想要的那个值就比较难说了. [方案

前端小组分享会之异步回调函数中的上下文

异步加载:又叫非阻塞加载,浏览器在下载执行js的同时,还会继续进行后续页面的处理.实现如:回调函数 .setTimeout . setInterval  回调函数(callback): 自己理解就是函数A里嵌套函数B B可能用到A中的变量,,B成为回调函数 function a (){ var x = 1; function b(){ console.log(++x) } b() } a() //2 上下文(Execution Context): 执行上下文(简称上下文)决定了Js执行过程中可以

python通过multiprocessing 实现带回调函数的异步调用的代码

下边代码段是关于python通过multiprocessing 实现带回调函数的异步调用的代码. from multiprocessing import Pool def f(x): if __name__ == '__main__': pool = Pool(processes=1) # Start a worker processes. result = pool.apply_async(f, [10], callback) # Evaluate "f(10)" asynchron

异步回调函数-创建进程的三种方式

回调函数 有两个类,A,B,在类A中调用B,在B中调用A的方法完成A的工作,那么这个在B类中调用的A的函数就称为回调函数. 异步回掉函数:类A将自己的工作交给类B后,继续执行剩下的程序,而B继续完成A交给的工作. 使用方法: 1.定义一个接口 2.A可以直接继承此接口,也可以定义一个内部类继承此接口: 定义一个方法,调用B中的方法 3.B中的方法调用A中的方法. //定义接口 public interface doJob { public void fillBlank(int a,int b,i