扩展阅读
  • WinDows8最新版文件夹加密
  • 怎么在Linux下改windows系统文件啊,我把windows的BOOT.INI改了,windows启动不了
  • 修改Windows硬盘分区名称
  • x-windows如何安装在linux(rdehat9)上面呢,是不是x-windows也分windows和linux版本的吗?
  • windows10玩游戏怎么样?唯一支持DirectX 12的windows
  • linux和windows串口问题!?linux向windows端发送,第一次write正常,继续write,windows接收到的就变成乱码了,这是什么原因??????
  • windows/windows 7/windows 8 下打开查看、修改及保存超大(GB级)文本文件及其它类型文件的工具-PilotEdit
  • 装了Linux和Windows,怎样默认进入Windows
  • Docker宣布支持Windows 10和Azure Windows Server
  • Linux与windows共存时,如何将Windows设置为默认启动系统?
  • win7/Windows7系统下载地址搜集整理
  • linux 、 unix给windows传送文件windows
  • Windows7自带防火墙设置:启动,关闭及高级设置
  • 怎样是编好的java application在windows上像windows应用程序一样直接运行
  • IE11设置IE兼容性视图及提升Windows 8.1中IE11兼容性的相关设置
  • windows 和linux双系统,重装windows后,无法启动linux?
  • Windows优化大师最新版 V7.99 Build 12.604发布
  • 如何将linux的一台机器加入windows 2000的域?并且通过一windows的机器上网?
  • Windows7 常用使用技巧
  • 为什么在安装了WINDOWS和LINUX的电脑上,重装WINDOWS会破坏MBR?
  • 如何在windows上远程连接centOS桌面
  • Linux + Windows2000 双启动,Windows2000起不来了,说是文件被破坏,进来看看……
  •  
    当前位置:  编程语言>c/c++

    Windows和Linux下C++类成员方法作为线程函数方法介绍

     
        发布时间:2014-1-14  


        本文导语:  Windows下c++类成员方法作为线程函数 类成员方法是一个比较特殊的函数,它在编译时会被转化成普通函数,比如有TMyClass类:class TMyClass{ void Func();};这个TMyClass::Func最终会转化成 void Func(TMyClass *this); 也就是说在...

      windowsc++成员方法作为线程函数

      类成员方法是一个比较特殊的函数,它在编译时会被转化成普通函数,比如有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
    #include
    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 : %dn",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*是自定义数据,也就是说它不能有其它功能)。

    Linux下类成员函数作为Pthread库线程函数

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

      第一个解决方法是使回调成员函数为静态。因为静态成员函数不带隐含式参数“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)(); // 成员函数指针
    };

      创建一个结构实例,用希望的对象地址和成员函数地址填充结构:    

    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():

    pthread_create (&ptid, NULL, intermediary, (void *)&a );

      pthread_create()调用函数intermediary()并将A的地址传递给它。intermediary()再从其指针参数中展开结构A并调用希望的成员函数。这种间接方式的

    处理可以安全地在单独线程中启动成员函数,即便是线程库不支持成员函数。如果需要调用不同类的不同成员函数,可以将结构A转换成类模板,将函数

    intermediary()转换成函数模板。从而编译器便会自动产生大多数样板文件代码。



    相关文章推荐:
  • 说说windows线程和linux线程的区别?
  • Linux的线程和windows 有什么区别?
  • 用pthread_create建立线程后如何让线程运行的函数在create完了之后才实际运行 相当与windows下的CREATE_SUSPENDED ??
  • 各位大侠,想问问驱动程序中(linux或者windows平台)可否使用线程?
  • 请问WINDOWS 和LINUX/UNIX 的进程、线程的区别
  • linux下的线程中有像windows的SuspendThread和SuspendThread的函数吗?
  • Windows下的PHP安装文件线程安全和非线程安全的区别
  • 如何在linux线程中实现windows下PostThreadMessage的功能
  • windows下面的线程代码怎么移植到unix下面去?
  • 一个windows下的C++工程,在linux下编译出错了 iis7站长之家
  • 关于Linux的线程和Windows的线程比较
  • 如何在windows 平台上实现消息队列(多线程环境)
  • ■■在Linux下有无类似Windows下Netants,Getright等多线程下载工具呀,免得我下载大多转到Windows下,谢谢!
  • 如何:对Windows 窗体控件进行线程安全调用


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3