C++ 类中使用多线程

参考资料:https://blog.csdn.net/shreck66/article/details/50409874

做项目的时候,应项目对接方的要求,需要在封装的类中启动线程,于是在定义一个成员函数startWork()负责线程的启动,结果程序报错,程序如下:

#include <iostream> 
#include <thread>
#include <windows.h>

using namespace std;

class TestCpp
{
public:
	void startWork();
	void work();
};


void TestCpp::work()
{
	int count = 0;
	while (1)
	{
		cout << count++ << endl;
		Sleep(500);
	}
}

void TestCpp::startWork()
{
	std::thread work_thread(work);
	work_thread.detach();
}

int main()
{
	TestCpp* the_test1 = new TestCpp;
	the_test1->startWork();

	while(1)
	{
		Sleep(1);
	}

	return 0;
}

报的错误是:

error C3867: “TestCpp::work”: 非标准语法;请使用 "&" 来创建指向成员的指针

原因是C++成员函数指针带有类命名空间,同时成员函数末尾是会被C++编译器加上可以接收对象地址的this指针参数。所以,我们std::thread的构造函数的参数不能是非静态成员函数,要改成静态成员函数。因此,在work函数的声明前面加上static,然后在构造thread类的时候输入参数去掉this指针(因为静态成员函数属于类本身,不属于对象)。代码如下:

#include <iostream> 
#include <thread>
#include <windows.h>

using namespace std;

class TestCpp
{
public:
	void startWork();
	static void work();
};


void TestCpp::work()
{
	int count = 0;
	while (1)
	{
		cout << count++ << endl;
		Sleep(500);
	}
}

void TestCpp::startWork()
{
	std::thread work_thread(work);
	work_thread.detach();
}

int main()
{
	TestCpp* the_test1 = new TestCpp;
	the_test1->startWork();

	while (1)
	{
		Sleep(1);
	}

	return 0;
}

但是,这样做有个新问题,就是作为线程的静态成员函数不能使用非静态成员变量,代码如下会报错:

#include <iostream> 
#include <thread>
#include <windows.h>

using namespace std;

class TestCpp
{
public:
	void startWork();
	static void work();

private:
	int n = 0;
};


void TestCpp::work()
{
	while (1)
	{
		cout << n++ << endl;
		Sleep(500);
	}
}

void TestCpp::startWork()
{
	std::thread work_thread(work);
	work_thread.detach();
}

int main()
{
	TestCpp* the_test1 = new TestCpp;
	the_test1->startWork();

	while (1)
	{
		Sleep(1);
	}

	return 0;
}

所以,需改给作为线程的静态成员函数传入类指针使用,在类里调用,加上this。代码如下:

#include <iostream> 
#include <thread>
#include <windows.h>

using namespace std;

class TestCpp
{
public:
	void startWork();
	static void work(TestCpp*);

private:
	int n = 0;
};


void TestCpp::work(TestCpp* ptr)
{
	while (1)
	{
		cout << (ptr->n)++ << endl;
		Sleep(500);
	}
}

void TestCpp::startWork()
{
	std::thread work_thread(work, this);
	work_thread.detach();
}

int main()
{
	TestCpp* the_test1 = new TestCpp;
	the_test1->startWork();

	while (1)
	{
		Sleep(1);
	}

	return 0;
}

或者不用把work声明为静态,直接创建一个静态的中间函数就行,用来连接startWork和work,作为startWork中的线程启动函数,内部实现只负责调用work函数。代码如下:

#include <iostream> 
#include <thread>
#include <windows.h>

using namespace std;

class TestCpp
{
public:
	void startWork();
	void work();
	static void threadFunc(TestCpp*);
};


void TestCpp::work()
{
	int count = 0;
	while (1)
	{
		cout << count++ << endl;
		Sleep(500);
	}
}

void TestCpp::threadFunc(TestCpp* arg)
{
	arg->work();
}

void TestCpp::startWork()
{
	std::thread work_thread(threadFunc, this);
	work_thread.detach();
}

int main()
{
	TestCpp* the_test1 = new TestCpp;
	the_test1->startWork();

	TestCpp* the_test2 = new TestCpp;
	the_test2->startWork();

	while (1)
	{
		Sleep(1);
	}

	return 0;
}

然后参考了上面最开始给的链接,有一种更好的解决方法,不必把线程函数定义为静态函数,直接用std::bind函数把函数和this指针绑定即可,代码见下:

#include <iostream> 
#include <thread>
#include <windows.h>

using namespace std;

class TestCpp
{
public:
	void startWork();
	void work();

private:
	int n = 0;
};


void TestCpp::work()
{
	while (1)
	{
		cout << n++ << endl;
		Sleep(500);
	}
}

void TestCpp::startWork()
{
	std::thread work_thread(std::bind(&TestCpp::work, this));
	work_thread.detach();
}

int main()
{
	TestCpp* the_test1 = new TestCpp;
	the_test1->startWork();

	while (1)
	{
		Sleep(1);
	}

	return 0;
}

好了,我们来总结一下刚才都发生了什么。首先,我把成员函数作为线程的输入函数报错了,然后我把线程函数改成声明为静态成员函数,但是如此一来,静态成员函数只能调用静态成员变量,所以还需要继续改进。然后发现有三种改进方法:第一种方法是对静态的线程函数加一个this指针指向当前成员;第二种方法是放弃把线程函数声明为static,改为声明一个中间函数为static,它作为新的线程启动函数,内部实现只有一行代码,就是启动work函数;第三种方法参考了网上的资料,同样不需要声明work为static,使用std::bind函数把work函数和this指针绑在了一起作为合成之后的线程函数。

猜你喜欢

转载自blog.csdn.net/IcdKnight/article/details/105663944
今日推荐