总结:this 在 pthread 包装里的作用
1. this 是什么
this 是一个指针,指向当前正在调用成员函数的那个对象。
cpp
class Thread {
int id;
void run() {
this->id = 1; // this 就是"这个对象"的地址
}
};
Thread a;
a.run(); // 这时 this == &a
关键:this 不是成员变量,而是成员函数隐藏的第一个参数。编译器会把
cpp
void Thread::run();
偷偷变成
cpp
void run(Thread* this);
调用 a.run() 时,实际是 run(&a)。这是编译器自动做的,你平时看不到。
2. 为什么 pthread_create 那里要传 this
pthread_create 是个 C 语言接口,它只认这种函数:
c
void* 函数名(void* 参数);
它不知道什么 this,也不会帮你传。
而你真正想跑的是某个对象的 run() 。问题是:线程启动后,包装器里没有 this,它不知道"我该跑哪个对象的 run"。
所以只能自己把 this 当普通参数塞进去:
cpp
pthread_create(&_tid, nullptr, &Thread::wrapper, this);
// ^^^^ 告诉它跑这个对象
到了线程里再取出来:
cpp
static void* wrapper(void* arg) {
Thread* self = static_cast<Thread*>(arg); // 还原出 this
self->run(); // 现在知道是谁了
return nullptr;
}
3. 为什么不直接把成员函数传进去
三种原因,从浅到深:
① 参数个数不对
run 实际有两个参数(this + 你的 arg),而 pthread_create 只会传一个。
② 类型不是同一种东西
cpp
void* (*)(void*) // 普通函数指针
void* (Thread::*)(void*) // 成员函数指针
C++ 里这是两个不同的类型,不能互相转换。连大小都不同(普通 8 字节,成员函数指针 16 字节)。
③ 调用时会崩
this 约定放在 rdi 寄存器,参数放 rsi。pthread_create 只往 rdi 塞参数,于是参数被当成 this,另一个参数没人传------运行时直接崩。
4. 所以包装器做了什么
cpp
static void* wrapper(void* arg) { ... }
static 的意思是"这个函数不属于任何对象 ",所以它没有隐藏的 this,类型就退化成了干净的 void*(*)(void*),pthread_create 能接受。
代价是:它自己拿不到对象了。所以用第 4 个参数把 this 送进去,函数里强转回来。
5. 一句话记法
this是编译器帮你偷偷传的隐藏参数。遇到 C 接口(它不认识这个约定)时,你只能自己手动传、自己手动还原------这就是包装器存在的理由。