了解回调函数的一些总结

回调函数第一次接触这个名词是在《linux C实战编程》的线程那一章上看见的,当时是condition.c中的一个程序不太理解,主要是其中调用了pthread_cleanup_push( )这个函数,其中是为了不可预见的程序退出导致占用资源得不到释放,通常使用回调函数来解决。于是开始关注了回调函数这个词。网上搜了很多资料,了解了很多,最后个人感觉它在以后的读程序中有很大的作用,无论是国外还是国内的很多代码都会采用回调函数,而且对回调函数的开发也是有很多例子。所以感觉这个东西可能以后会用到,自己先了解了下。


pthread_cleanup_push( ) /pthread_cleanup_pop( )使用

以小见大吧,首先先讲讲我从线程里怎么认识这个回调函数的。
pthread_cleanup_push( )和pthread_cleanup_pop( )是必须要成对出现的,在线程里主要有两种退出方式,一种是正常退出,另一种是非正常的退出。
主动退出可以采用pthread_exit()这个函数,或者从线程函数中return都能够从线程中退出。非正常退出就是受到了其他线程的干扰或者是一段错误的时候就退出了。
关于这两个函数的使用,自己先引用下别人的东西吧,感觉人家总结的挺好的。

pthread_cleanup_push()/pthread_cleanup_pop()采用先入后出的栈结构管理,void routine(void *arg)函数在调用pthread_cleanup_push()时压入清理函数栈,多次对pthread_cleanup_push()的调用将在清理函数栈中形成一个函数链,在执行该函数链时按照压栈的相反顺序弹出。execute参数表示执行到pthread_cleanup_pop()时是否在弹出清理函数的同时执行该函数,为0表示不执行,非0为执行;这个参数并不影响异常终止时清理函数的执行。
pthread_cleanup_push()/pthread_cleanup_pop()是以宏方式实现的,这是pthread.h中的宏定义:#define pthread_cleanup_push(routine,arg)
{ struct _pthread_cleanup_buffer _buffer;
_pthread_cleanup_push (&_buffer, (routine), (arg))#define pthread_cleanup_pop(execute)
_pthread_cleanup_pop (&_buffer, (execute)); }
可见,pthread_cleanup_push()带有一个”{“,而pthread_cleanup_pop()带有一个”}”,因此这两个函数必须成对出现,且必须位于程序的同一级别的代码段中才能通过编译。在线程宿主函数中主动调用return,如果return语句包含在pthread_cleanup_push()/pthread_cleanup_pop()对中,则不会引起清理函数的执行,反而会导致segment fault。

然后此时这个函数会在解锁不成功,或者在互斥锁中的pthread_cond_wait( )函数的时候,解锁和重现加锁后,这个函数出现异常,造成wait函数执行取消,导致解锁不成功的时候,就可以使用pthread_cleanup_push中的第一个参数,一个函数指针指向解锁函数,传入解锁函数的入口地址。在解锁不成功的时候就调用这个函数。

所以从这里就可以看出回调函数调用的那个函数要执行,是需要一定条件的,如果条件成立的时候才调用回调函数里面的那个函数,如果条件不成立是不调用的。

回调函数的理解

回调函数是通过调用函数指针的函数。在达到一定条件的时候,它通过该函数指针指向的函数,实行函数指针指向的函数功能的一种函数。回调函数的实行是通过回调机制这种操作实现的。通俗易懂就是一个函数它的形式参数中含有一个函数指针,通过操作这个函数指针来实现整个过程的函数就是回调函数(注意划分下主谓宾……)

摆上百度上的定义:

如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
机制:⑴定义一个回调函数;⑵提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者;⑶当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。

对应上面的那个pthread_cleanup_push()/pthread_cleanup_pop()其实也就能够理解了这种机制的好处。它是首先被传入之后等待一个合适的时候才被调用的函数。它在应用和库之间灵活性很大,也是在知乎上了解到的,但是它的运用不至于应用和库之间,看了下也感觉有点复杂,但是引用了一个最简单直白形象的比喻。

常溪玲
A geeky nerd.
收录于 编辑推荐 · 2734 人赞同了该回答
你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。
发布于 2011-08-06
2.7K
96 条评论

看了很多评论(后面还扯出来硬件中断与回调的区别……)感觉回调函数这个总体是调用回更高的层级,从底层到高层的一个过程。而回调函数是一个中间的过度层。
比如从pthread_cleanup_push( )/pthread_cleanup_pop( )来举例,在主函数中。

pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut);
pthread_mutex_lock(&mut);
count++;
pthread_mutex_unlock(&mut);
pthread_cleanup_pop(0);

首先main函数为第一层,加锁解锁也为第一层函数,然后push和pop都是第二层的,所以第一层调用了第二层的,第二层又回调了执行第一层的函数。这个就是一个回调机制。

#include <stdio.h>

void printWelcome(int len)
{
       printf("欢迎欢迎 -- %d/n", len);
}

void printGoodbye(int len)
{
       printf("送客送客 -- %d/n", len);
}

void callback(int times, void (* print)(int))
{
       int i;
       for (i = 0; i < times; ++i)
       {
              print(i);
       }
       printf("/n我不知道你是迎客还是送客!/n/n");
}
void main(void)
{
       callback(10, printWelcome);
       callback(10, printGoodbye);
       printWelcome(5);
}

再引用别人的一个回调函数,此时函数callback函数为B层,main函数和print*函数为A层,A层调用了B层的回调函数callmeback,而B层的回调函数调用了A层的实现函数print。

所以通过两个例子,这个中间层的函数,回调函数就是一个桥梁。就像上面的例子,售货员留号码的例子,如果你不登记回调函数,不留下电话,就算是货到了也联系不到你的。以上是自己的在网上找的一些资料,和自己的理解。

猜你喜欢

转载自blog.csdn.net/qq_36573828/article/details/76767513