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

线程中调用成员函数
本文探讨如何在单独线程中调用C++类成员函数的问题,提出了两种解决方案:一是使用静态成员函数,二是通过中介函数间接调用非静态成员函数,并详细介绍了这两种方法的具体实现。
在单独线程中执行对象成员函数 (转)[@more@]问题的提出:
  实际上所有线程都是用来处理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()转换成函数模板。从而编译器便会自动产生大多数样板 文件代码。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10752043/viewspace-988405/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/10752043/viewspace-988405/

### 动态调用类成员函数并放入线程执行C++ 中,动态调用类的成员函数并将其放入线程执行可以通过多种方法实现。以下是几种常见的实现方式: #### 方法一:使用 `std::bind` 动态绑定成员函数 `std::bind` 提供了一种灵活的方式来动态绑定成员函数及其参数,并将结果传递给 `std::thread`。 ```cpp #include <iostream> #include <thread> #include <functional> class MyClass { public: void memberFunction(int value) { std::cout << "Thread ID: " << std::this_thread::get_id() << ", Value: " << value << std::endl; } }; int main() { MyClass obj; // 使用 std::bind 动态绑定成员函数和参数 auto boundFunction = std::bind(&MyClass::memberFunction, &obj, 42); std::thread t(boundFunction); // 将绑定的结果传递给 std::thread t.join(); return 0; } ``` 这种方式通过 `std::bind` 显式地绑定了成员函数指针、对象实例以及参数[^3]。 #### 方法二:使用 Lambda 表达式封装成员函数调用 Lambda 表达式提供了一种简洁的方式,可以动态捕获对象实例并调用其成员函数。 ```cpp #include <iostream> #include <thread> class MyClass { public: void memberFunction(int value) { std::cout << "Thread ID: " << std::this_thread::get_id() << ", Value: " << value << std::endl; } }; int main() { MyClass obj; // 使用 Lambda 表达式动态调用成员函数 std::thread t([&obj]() { obj.memberFunction(42); }); t.join(); return 0; } ``` 通过 Lambda 表达式,可以在不显式使用 `std::bind` 的情况下实现成员函数的动态调用[^3]。 #### 方法三:通过函数指针间接调用成员函数 虽然直接传递成员函数指针给 `std::thread` 是不可能的,但可以通过静态成员函数或全局函数作为中来间接调用成员函数。 ```cpp #include <iostream> #include <thread> class MyClass { public: void memberFunction(int value) { std::cout << "Thread ID: " << std::this_thread::get_id() << ", Value: " << value << std::endl; } static void staticWrapper(MyClass* instance, int value) { if (instance) { instance->memberFunction(value); } } }; int main() { MyClass obj; // 通过静态成员函数间接调用成员函数 std::thread t(&MyClass::staticWrapper, &obj, 42); t.join(); return 0; } ``` 这种方法避免了为每个成员函数编写单独的静态中函数的需求[^1]。 #### 方法四:使用 `std::function` 包装成员函数 `std::function` 提供了一种通用的方式来存储和调用可调用对象,包括成员函数。 ```cpp #include <iostream> #include <thread> #include <functional> class MyClass { public: void memberFunction(int value) { std::cout << "Thread ID: " << std::this_thread::get_id() << ", Value: " << value << std::endl; } }; int main() { MyClass obj; // 使用 std::function 包装成员函数 std::function<void()> func = std::bind(&MyClass::memberFunction, &obj, 42); std::thread t(func); // 将包装后的函数传递给 std::thread t.join(); return 0; } ``` 这种方式结合了 `std::bind` 和 `std::function` 的功能,提供了更高的灵活性[^3]。 --- ### 注意事项 - 在多线程环境中,确保对共享资源的访问是线程安全的。 - 如果成员函数修改了类的非静态成员变量,则必须确保这些变量在线程间的访问是同步的。 - 对象的生命周期必须长于线程的生命周期,以避免悬空指针问题[^1]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值