参考:http://blog.youkuaiyun.com/braveyly/article/details/3446472
对于”在类里面的成员函数创建线程怎么搞“都有两三个月的疑问了,一直没想到什么好的方法。对于创建线程的调用函数归属问题不太清楚,也没什么时间做个实验。
下面的实验借鉴链接中的博客的思想,实验环境为ubuntu 11.04, Emacs。
补充:
Linux下,创建线程为:pthread_create(); 回调函数的形式为:void * thread_proc(void * arg);
Windows下,创建线程为:CreateThread(); 回调函数形式为:DWORD WINAPI thread_proc(LPVOID lpParam);
一共有三种方法:
1. 这种情况,一般是将线程函数申明为静态成员变量,写入口函数时,指明该入口函数所在的类
在类中定义的成员函数,VC在编译时会强加一个this指针,通过函数名无法定位该入口函数。将该成员函数声明为static类型,可以将this指针除去。
缺点:static成员函数只能访问static成员。
在类A的成员函数中创建线程,代码如下:
pthread_t threadID;
int err=pthread_create(&threadID, NULL, A::thread_proc, NULL);
声明时:
class A
{
static void * thread_proc(void * arg);
};
注意:入口函数的输出类型和输入类型不能变化。
注意:友元函数在头文件中声明,在cpp文件中定义。如果直接定义在头文件中,链接的时候会有多重定义错误提示。
3. 可以对成员函数实现回调,并访问非静态成员的。
这种方法充分利用了传给回调函数的指针,将类中的成员打包发送给了回调函数,从而实现访问。
(下面没有进行试验,部分需要改动)
如下所示,这是为了实现线程函数访问类成员而实现的类。比MFC的实现方法好象要好一点。
class base;
//?
typedef int (base::*fnCallBack)(void *p);
//用来封装回调类的信息
struct callback
{
void *param;
fnCallBack *pfuc;
base *pThis; //存放类的信息
};
class base
{
//回调函数,没有试验,但应该按照回调函数的标准来定义
static int myThreadfuc(void * p)
{
struct callback *p1=(struct callback *)p;
//将封装后的信息解包
base * pthis=p1->base;
fnCallBack *pfuc=p1->pfuc;
void * param=p1->param;
//运行实际要运行的函数
int i=(pthis->*pfuc)(param);
delete p;
return i;
}
public:
void myCreateThread(fnCallBack pfuc,void *param)
{
struct callback *p=new struct callback;
//把封装后的类的成员以及回调函数打包
p.param=param; //客户要传给实际要运行函数的参数
p.pThis=this; //保存类的指针
p.pfuc=pfuc; //保存实际要运行的函数
//创建线程,注意其他参数自己补全
::CreateThread(myThreadfuc,p);
}
virtual int myCallBack(void *p)
{
printf("It's base class./n");
return 0;
}
};
class derived:public base
{
int myCallBack(void *p)
{
printf("It's derived class/n");
}
};
void myCreateThreadImitate(fnCallBack fuc,void *p)
{
(*fuc)(p);
}
void main()
{
base p;
char *param;
p.myCreateThread(&(base::myCallBack),param);
derived p2;
p2.myCreateThread(&(base::myCallBack),param);
}