参考资料: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指针绑在了一起作为合成之后的线程函数。