如何在類中定義線程函數

在類裏面定義了幾個線程函數,用以訪問類成員,編譯的時候遇到了“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!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章