把C++类成员方法直接作为线程回调函数

 

把C++类成员方法直接作为线程回调函数

原文链接:http://blog.csdn.net/waiting4you/article/details/2000796

我以前写线程时要么老老实实照着声明写,要么使用C++类的静态成员函数来作为回调函数,经常会因为线程代码而破坏封装.之前虽然知道类成员函数的展开形式,但从没想过利用过它,昨天看深入ATL时无意中学会了这一招:) 

类成员方法是一个比较特殊的函数,它在编译时会被转化成普通函数,比如有TMyClass类:
class TMyClass{
    void Func();
};

这个TMyClass::Func最终会转化成 void Func(TMyClass *this); 也就是说在原第一个参数前插入指向对象本身的this指针。

我们可以利用这个特性写一个非静态类成员方法来直接作为线程回调函数,先看_beginthread函数的定义:
unsigned long _RTLENTRY _EXPFUNC _beginthread (void (_USERENTRY *__start)(void *),unsigned __stksize, void *__arg);
其中的第一个参数就是作为线程执行主体的回调函数。它的原型是:void Func(void *),这个void*参数是作为自定义数据传入的。对比一下上面所说的TMyClass::Func的最终形式,它正好可以符合这里的要求。

现在做个实验:
#include <stdio.h>
#include <process.h>

class TMyClass{
    int m_nCount;
    int m_nId;
public:
    TMyClass(int nId,int nCount)
        :m_nId(nId),m_nCount(nCount)
    {
    }

    void _USERENTRY ThreadProc()            // 类成员方法
    {
        for(int i=0; i<m_nCount; i++)       // 根据m_nCount成员打印一排数字
        {
            printf("Class%d : %d/n",m_nId,i);
        }
    }
};

int main(int argc, char* argv[])
{
    union {                                // 联合类,用于转换类成员方法指针到普通函数指针(试过编译器不允许在这两种函数之间强制转换),不知道有没有更好的方法。
        void (_USERENTRY *ThreadProc)(void *);
        void (_USERENTRY TMyClass::*MemberProc)();
    } Proc;                                // 尽管联合里的两种函数类型现在看起来有很大不同,但它们的最终形式是相同的。

    TMyClass MyClass1(1,10),MyClass2(2,5); // 产生两个TMyClass对象

    Proc.MemberProc = &TMyClass::ThreadProc;   // 转换,Proc.ThreadProc就是对应的普通函数指针了

    _beginthread(Proc.ThreadProc,4096,&MyClass1);   // 开始线程,这里的Proc.ThreadProc实际上是TMyClass::ThreadProc, 它要的this指针是我们给的&MyClass1。
    _beginthread(Proc.ThreadProc,4096,&MyClass2);
    system("pause");
    return 0;
}

运行!神奇吧?:-)

其实不止线程回调函数,其实只要是形如Func(void*,...)的回调函数都可以用这种方法直接使用类成员方法。(前提是第一个void*是自定义数据,也就是说它不能有其它功能)。

C++中,多线程回调函数通常通过多种方式实现,最常见的是使用`std::thread`库提供的成员函数`detach`和`async`,或者是通过`std::function`, `std::bind`或者lambda表达式来传递函数引用给线程。这里分别介绍这两种常见的方法: 1. **使用`std::thread::detach`和`std::future`** - 创建线程时,你可以将一个函数作为参数传递给`std::thread`的构造函数,例如: ```cpp void threadFunction(int param) { // 线程执行的代码 } std::thread t(threadFunction, 42); // 传入回调函数和参数 // 线程启动后,主线程继续执行 t.detach(); // 将线程从主进程分离出去 // 如果需要异步的结果,可以使用`std::future`: auto future = t.get_future(); // ... 然后在你需要的时候获取结果,比如通过`future.wait_for`和`future.get()` ``` 2. **使用`std::function`或`std::bind`** - `std::function`允许你在运行时动态地存储和执行一个函数: ```cpp std::function<void()> callback = std::bind(&threadFunction, 42); std::thread t(callback); // 线程启动时执行该回调函数 t.join(); // 等待线程结束 ``` 或者 ```cpp void (*callback)(int) = &threadFunction; std::thread t(callback, 42); // 直接传递指向函数的指针 ``` 3. **使用Lambda表达式(C++11及以上版本)** - 利用现代C++的特性,你可以直接在构造线程时定义一个匿名函数: ```cpp std::thread t([param](void){ threadFunction(param); }, 42); // 匿名函数作为参数 ``` 在上述所有方法中,回调函数都是异步执行的,当线程完成工作后,如果没有指定特定的方式去接收结果(如`std::future`),那么通常会立即返回,而不会阻塞主线程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值