如何在类中定义线程函数

31 篇文章 0 订阅
20 篇文章 1 订阅

在类里面定义了几个线程函数,用以访问类成员,编译的时候遇到了“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!

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值