回调函数

之前对回调函数理解一直不到位,需要深入分析一下。
一般函数都是系统提供或程序员自定义的,让程序员使用的。但回调函数恰恰相反,它是程序员定义(注册),在特定条件(常常是用户触发)发生时由系统API调用的,是通过函数指针实现调用的。函数定义在高层,调用在底层。

Linux信号处理机制就是利用回调函数实现的,例如signaction某个形参就有一个成员是函数指针。

1
2
3
4
5
6
7
8
9
10
11
12
void func(int n)
{
printf("signal %d catched !\n",n);
}
int main()
{
struct sigaction act;
act.sa_handler = func;
sigaddset(&act.sa_mask,SIGQUIT);
act.sa_flags = 0;
sigaction(SIGINT,&act,NULL);
}

当程序运行后,按Ctrl+C会发送SIGINT信号,然后内核调用函数func,输出文本。

类的成员函数做回调函数

由于this指针的作用,使得将一个CALLBACK型的成员函数作为回调函数安装时就会因为隐含的this指针使得函数参数个数不匹配,从而导致回调函数安装失败。定义类成员函数时,在该函数前加CALLBACK即可将其定义为回调函数。

  1. 类的静态成员函数实现回调函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
void func(int sig)
{
cout << endl;
cout << "signal: "<<sig<<endl;
if(sig == 15)
cout << "SIGTERM"<<endl;
else
cout << "SIGINT"<<endl;
exit(0);
}

class Foo
{
public:
static void func(int sig)
{
cout << endl;
cout << "signal: "<<sig<<endl;
if(sig == 15)
cout << "receive signal SIGTERM"<<endl;

exit(0);
}
};

int main()
{
signal(SIGINT, func);
signal(SIGTERM, Foo::func); // 第二个参数也可以是func
while(1) // 设法阻塞
sleep(1);
return 0;
}

从终端启动程序,会阻塞。按下Ctrl+C,会触发SIGINT信号。执行pkill命令,会触发SIGTERM信号。