http://www.yesky.com/345/1658345.shtml
问题的提出:
实际上所有线程都是用来处理C函数的,而不是C++类成员函数。标准库中提供一个API函数,这个函数以回调函数指针作为线程的执行代码并在单独的线程中调用回调函数。问题是在这样的线程库中不能创建执行对象成员函数的线程;只能使用普通的函数。因此,下列代码是失败的:
// 启动线程库函数的线程 #include "class1.h" int func (void *param ) |
函数thr_create()需要回调函数的地址,void* 作为地址参数被传递到回调函数,同时传递的参数还有thread_t变量的指针(有关回调函数和函数指针的概念参见VC知识库中另外的文章)。
上面的代码之所以编译失败是因为传递到thr_create()的第一个参数是类class1的成员函数指针,而不是普通函数指针。从概念上讲,普通函数和类成员函数是两个完全不同的事情。即使进行强制类型转换也不行。那么如何解决这个问题呢?
方法一:使用静态成员函数
第一个解决方法是使回调成员函数为静态。因为静态成员函数不带隐含式参数“this”。因此,可以将其参数中的地址当作是普通函数的指针来使用。如果要从静态成员函数中访问对象的数据成员,显式传入对象的地址即可。例如:
class Hack void Hack::func(Hack * pthis) |
这个方法在大多数情形下都能行得通,但有时候成员函数不能声明为静态,也就是说成员函数是虚函数或者正在使用不能修改的第三方类。遇到这种情况时,用方法一解决问题就比较难了。
方法二:处理非静态成员函数
假设需要在单独的线程中调用类Hack的非静态成员函数func2()。不用直接传递成员函数的地址到thr_create(),声明一个带 void* 参数的普通函数intermediary(void*),然后调用它:
void intermediary(void*); |
接着创建一个结构,结构定义如下:
struct A { Hack * p; //类对象指针 void (Hack::*pmf)(); // 成员函数指针 }; |
创建一个结构实例,用希望的对象地址和成员函数地址填充结构(有关详细的成员函数指针内容请参见VC知识库中的其它文章)。
A a; // 结构实例 Hack h; // 创建对象 //填充结构 a.p = & h; a.pmf = &Hack::func2; // 取成员函数地址 |
现在回过头来实现intermediary()函数:
void intermediary(void* ptr) { A* pa=static_cast < A* > (ptr); // 强制转换 p 为 A* Hack* ph=pa->p; // 从A中析取Hack对象地址 void (Hack::*pmf)()=pa->pmf; // 析取 ptr 到成员函数 (ph->*pmf)(); // 调用成员函数 } |
最后将intermediary()的地址传递到thr_create():
thr_create (intermediary, (void*) &a, &t1 ); |
thr_create()调用函数intermediary()并将A的地址传递给它。intermediary()再从其指针参数中展开结构A并调用希望的成员函数。这种间接方式的处理可以安全地在单独线程中启动成员函数,即便是线程库不支持成员函数。如果需要调用不同类的不同成员函数,可以将结构A转换成类模板,将函数intermediary()转换成函数模板。从而编译器便会自动产生大多数样板文件代码。
http://blog.sina.com.cn/s/blog_4cce4f6a0100m6jw.html
pthread_create 是 POSIX 标准下创建线程的函数,函数原型是:
int pthread_create(pthread_t *thread, pthread_attr_t *attr, void*(*start_routine)(void *), void *arg);
在 C 中,这个函数使用很简单,只要定义一个参数和返回值均为 void * 类型的函数,使用函数名字作为参数即可。就算不完全符合,可以使用 (void *(*)(void *)) 将其强制转换为符合类型检查规格的函数指针。但是,类的非静态成员函数隐含 this 指针作为第一个参数,所以参数完全不可能转化为 void * 类型,而 C++ 的类型检查要比 C 严格许多。由于我原来写的代码是 C 风格的,自然不会出现类型不符的问题,现在将线程开始函数封装到一个模板类中,再创建线程的时候就不能满足需要了。
方法一:定义线程开始函数为类的静态成员函数(static member function),这样就不隐含 this 指针了,然后将 this 指针从 pthread_create 最后一个参数传给开始函数,在函数中将 void * 类型的 this 指针强制转换为类指针。看来静态成员函数还是有些妙用的。
方法二:
template <typename TYPE, void (TYPE::*_RunThread)() >
void* _thread_t(void* param)
{
TYPE* This = (TYPE*)param;
This->_RunThread();
return NULL;
}
class MyClass
{
public:
MyClass();
void _RunThread();
private:
pthread_t tid;
};
void MyClass::_RunThread()
{
this->DoSomeThing();
//...
}
MyClass::MyClass()
{
pthread_create(&tid, NULL, _thread_t<MyClass, &MyClass::_RunThread>, this);
}
函数模版不单可以替换类型本身,还能替换类型的成员函数。
注意:1、名称只能是_RunThread,不能在指定模版参数的时候修改;
2、_RunThread只能是public的,除非把_thread_t定义到MyClass的内部。