Linux线程创建函数的定义是这样的:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg);
其中的第三个参数void *(*start_routine)(void *)
该如何理解?
一、函数指针与指针函数:
函数指针:
本质是指针,指向一个函数的指针。
用法:
int (*p)(int, int); //定义一个函数指针
int func(int a, int b) {
}
p = &func;
指针函数:
本质是一个函数,函数的返回值是一个指针。
用法:
int *p(void) {
int *addr = (int*)malloc(sizeof(int));
return addr;
}
int main() {
int *mem = p(void);
return 0;
}
几点注意事项:
-
下面这种写法是绝对错误的:
void (*p)(void) { }
因为这是在定义一个函数指针,它只是一个指针,后面就不能有函数体。
-
&func 与 func 的区别:
函数名与对函数名取址有什么区别:
它们的值是相同的,但是表达的意思不同:func是函数的首地址,它的类型是void(),&func表示一个指向函数func这个对象的地址,它的类型是void(*)(),因此它们所代表的地址是一样的,但类型不一样。
按照&运算符本来的意义,它要求其操作数是一个对象,但函数名不是对象(函数才是对象),本来&func是非法的,但很久以前许多编译器就允许这么做。
总结:
在平时使用时,当需要传入一个函数指针做参数,直接传入函数名即可,不需要&func这样的写法。
二、pthread_create:
再来看pthread_create()这个函数的第三个参数就比较好理解了:
void *(*start_routine)(void *)
要传入的参数是一个函数指针:(*start_routine),
这个函数的返回值类型是 (void *),入参类型是 (void *)
所以,pthread_create的使用方法是这样的:
void *thread_callback(void *arg) {
//do something
}
int main() {
pthread_create(&tid, NULL, thread_callback, &arg);
}
三、回调函数:
1. 回调函数作用是什么?
回调函数最大的作用,就是 解耦。
如果只是为了在一个函数中调用另一个函数,普通函数也是完全可以实现的(直接在函数参数中调用另一个函数名即可),库函数只需要提供一个接口给使用者调用:
void Library(void *(*Callback)(void *)) {
}
这样一来,只要使用者改变传进库函数的参数不同,就可以实现不同的功能,非常的灵活,并且没有丝毫改变库函数的实现,这就是解耦。
回过头来想一想,pthread_create就是这样的一种使用回调函数的方式:
pthread线程库提供一个接口pthread_create供应用程序调用,应用程序将不同的线程回调函数(入口函数)传入进去,即可实现不同的线程功能:
void *pthread_A(void *arg) {
}
void *pthread_B(void *arg) {
}
int main() {
pthread_create(&tid_a, NULL, pthread_A, NULL);
pthread_create(&tid_b, NULL, pthread_B, NULL);
}
参考内容: