在类里面定义了几个线程函数,用以访问类成员,编译的时候遇到了“error: invalid use of non-static member function”。测试代码如下:
#include <iostream>
#include <pthread.h>
#include <unistd.h>
class MyClass
{
public:
MyClass()
{
num = 0;
}
int num;
// Define a thread function
void* increase_num(void *param)
{
while(num < 100)
{
num++;
usleep(10000);
}
return NULL;
}
// Define a start function to call the thread function
void run()
{
pthread_t thread_inc;
pthread_create(&thread_inc, NULL, increase_num, NULL);
pthread_join(thread_inc, NULL);
}
};
int main()
{
MyClass my_class;
my_class.run();
std::cout << my_class.num << std::endl;
return 0;
}
编译结果:
分析发现,线程函数在编译时必须知道函数的入口地址,而类中的普通成员函数入口地址在类定义阶段是未知的,只有在类实例化之后才会为其分配内存空间。
C++程序的内存格局通常包含四个区,分别是:全局数据区、代码区、栈区、堆区。
类成员函数是放在代码区。类的静态成员在类定义时已经在全局数据区分配了内存;而非静态成员则是在实例化过程中才在栈区或堆区为其分配内存,为每个对象生成一个拷贝。类的非静态成员函数都内涵了一个指向类对象的this指针,只有生成类对象后this指针才有实际值。
那么,怎样解决类成员函数作为线程函数的问题呢?网上搜了一下,有几种方式,尝试了两种比较简单的方式,都行得通。
1. 将线程函数定义成静态类型
如果把线程函数改成静态成员函数会怎样?我们把上面代码中的语句
void* increase_num(void *param)
改成
static void* increase_num(void *param)
编译结果:
静态成员函数不能访问普通的类成员变量!
静态成员函数因为在类定义的时候就已经分配了内存,因此自然可以作为线程函数使用。但是存在一个问题,静态成员函数只能直接访问类的静态成员,而无法访问类的非静态成员。这是因为,静态成员函数在编译时会被编译器转换为不带this指针的全局函数,因此无法直接访问类的普通成员。了解了这一点,那么我们可以通过传递this指针的方式来解决这个问题。
修改原始代码中的类定义:
class MyClass
{
public:
MyClass()
{
num = 0;
}
int num;
// Define a thread function
static void* increase_num(void *param)
{
MyClass *p = (MyClass *)param;
while(p->num < 100)
{
p->num++;
usleep(10000);
}
return NULL;
}
// Define a start function to call the thread function
void run()
{
pthread_t thread_inc;
pthread_create(&thread_inc, NULL, increase_num, this);
pthread_join(thread_inc, NULL);
}
};
编译通过,运行结果正常。
2. 将线程函数定义为友元函数
友元函数定义在类外部,并非类的成员函数,但它可以访问类的private和protected成员,因此也可以将线程函数定义为类的友元函数。程序代码如下:
#include <iostream>
#include <pthread.h>
#include <unistd.h>
class MyClass
{
public:
MyClass()
{
num = 0;
}
// Define a thread function
friend void* increase_num(void *param);
// Define a start function to call the thread function
void run();
void print_num();
private:
int num;
};
void* increase_num(void *param)
{
MyClass *p = (MyClass *)param;
while(p->num < 100)
{
p->num++;
usleep(10000);
}
return NULL;
}
void MyClass::run()
{
pthread_t thread_inc;
pthread_create(&thread_inc, NULL, increase_num, (void*)this);
pthread_join(thread_inc, NULL);
}
void MyClass::print_num()
{
std::cout << num << std::endl;
}
int main()
{
MyClass my_class;
my_class.run();
my_class.print_num();
return 0;
}
编译、执行都OK!