在单独线程中执行对象成员函数

转载 2006年06月12日 11:48:00
问题的提出:

   实际上所有线程都是用来处理C函数的,而不是C++类成员函数。标准库中提供一个API函数,这个函数以回调函数指针作为线程的执行代码并在单独的线程中调用回调函数。问题是在这样的线程库中不能创建执行对象成员函数的线程;只能使用普通的函数。因此,下列代码是失败的:

// 启动线程库函数的线程
int thr_create (void (*pf)(), void* prm, thread_t* pth);

#include "class1.h"

int func (void *param )
{
thread_t t1;
// 下列调用导致编译器错误: "Cannot convert ''void (class1::*)()'' to ''void (*)()''"
// 意思是不能转换类型
return thr_create ( &class1::some_method, param, &t1);
}


   函数thr_create()需要回调函数的地址,void* 作为地址参数被传递到回调函数,同时传递的参数还有thread_t变量的指针(有关回调函数和函数指针的概念参见VC知识库中另外的文章)。

   上面的代码之所以编译失败是因为传递到thr_create()的第一个参数是类class1的成员函数指针,而不是普通函数指针。从概念上讲,普通函数和类成员函数是两个完全不同的事情。即使进行强制类型转换也不行。那么如何解决这个问题呢?

   方法一:使用静态成员函数

   第一个解决方法是使回调成员函数为静态。因为静态成员函数不带隐含式参数“this”。因此,可以将其参数中的地址当作是普通函数的指针来使用。如果要从静态成员函数中访问对象的数据成员,显式传入对象的地址即可。例如:

class Hack
{
private:
int x;
public:
int get_x();
static void func(Hack * pthis); // 静态成员函数
void func2(); // 非静态成员函数
};

void Hack::func(Hack * pthis)
{
int y = pthis->get_x(); // 访问对象的数据成员
}


   这个方法在大多数情形下都能行得通,但有时候成员函数不能声明为静态,也就是说成员函数是虚函数或者正在使用不能修改的第三方类。遇到这种情况时,用方法一解决问题就比较难了。

   方法二:处理非静态成员函数

   假设需要在单独的线程中调用类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()转换成函数模板。从而编译器便会自动产生大多数样板文件代码。

在单独线程中执行对象成员函数

问题的提出:    实际上所有线程都是用来处理C函数的,而不是C++类成员函数。标准库中提供一个API函数,这个函数以回调函数指针作为线程的执行代码并在单独的线程中调用回调函数。问题是在这样的线程库中...
  • antswallow
  • antswallow
  • 2009年06月25日 11:58
  • 324

在单独线程中执行对象成员函数

问题的提出:    实际上所有线程都是用来处理C函数的,而不是C++类成员函数。标准库中提供一个API函数,这个函数以回调函数指针作为线程的执行代码并在单独的线程中调用回调函数。问题是在这样的线程库中...
  • sxslyy
  • sxslyy
  • 2007年08月01日 10:40
  • 334

使代码运行在一个单独的线程中的方法

QThread
  • tony2278
  • tony2278
  • 2017年10月30日 13:48
  • 112

在类中使用类成员函数创建线程

demo书写大概步骤:      1》创建一个类,在类中创建一个函数      2》在构造函数中创建线程,使用类中的成员函数 类中代码:  类头: #pragma once #include cla...
  • qq_21000273
  • qq_21000273
  • 2016年04月10日 15:54
  • 1006

在MFC中类内部建立线程处理函数以便调用类的成员函数和变量

在用MFC做开发时,有时遇到些工作线程zhong
  • xinsuixiaofeiyu
  • xinsuixiaofeiyu
  • 2014年08月17日 19:33
  • 1844

C++中类的成员函数作为 pthread_create的线程函数

在C++的类中,普通成员函数作为pthread_create的线程函数就会出现参数问题,因为其不能作为pthread_create的线程函数,如果要作为pthread_create中的线程函数,必须是...
  • hsd2012
  • hsd2012
  • 2016年04月21日 11:42
  • 2849

C++ 11 线程调用类的成员函数解决办法

在C++中,_beginthreadex 创建线程是很麻烦的。要求入口函数必须是类的静态函数。 通常,可以采用thunk,或者模板来实现。 因C++ 11中引入了 std::async ,可以很好...
  • badboy518
  • badboy518
  • 2017年01月31日 17:15
  • 1147

boost线程之类成员函数

首先,是准备工作,包含头文件 #include #include #include #include using namespace std; //线程休眠,毫秒级 #define B...
  • zhuxian2009
  • zhuxian2009
  • 2015年09月02日 17:39
  • 965

类成员函数作为线程函数的几种方法

首先,类成员函数是不能够直接被当做线程的成员函数使用。 原因是,类中定义的成员函数,编译器会给其加上this指针。 解决方案有如下: 1.把成员函数声明成static类型,去掉this指针。但是...
  • yzl20092856
  • yzl20092856
  • 2015年10月05日 22:19
  • 282

java线程对单个对象的共享的一些方式

最近看了关于java多线程的一些知识,今天总结一下。主要总结的是java多线程对于单个对象共享的控制,主要从可见性、发布逸出、线程封闭、不变性、安全发布5个方面来进行总结,看的书籍为《Java并发边编...
  • u013159433
  • u013159433
  • 2015年12月18日 18:06
  • 2356
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:在单独线程中执行对象成员函数
举报原因:
原因补充:

(最多只允许输入30个字)