zoukankan      html  css  js  c++  java
  • 类成员函数作为pthread_create函数参数

    from:http://www.cnblogs.com/shijingxiang/articles/5389294.html

     近日需要将线程池封装成C++类,类名为Threadpool。在类的成员函数exec_task中调用pthread_create去启动线程执行例程thread_rounter。编译之后报错如下:

    spfs_threadpool.cpp: In member function ‘int Threadpool::exec_task(task*)’:

    spfs_threadpool.cpp:174: error: argument of type ‘void* (Threadpool::)(void*)’ does not match ‘void* (*)(void*)’

        出现类型不匹配的问题。因为pthread_create需要的参数类型为void* (*)(void*),而thread_rounter作为类的成 员函数时其类型是void* (Threadpool::)(void*)的成员函数指针。我们知道类的成员函数在经过编译器处理之后,会变成带有 this指针参数的全局函数,所以类型注定是不会匹配的。但是如果将thread_rounter声明为static类型,那么编译器会将static形 式的函数,转换成不带this指针的全局函数,所以其类型可以与pthread_create需要的参数类型相匹配。但是类的静态成员函数无法访问类的非 静态成员,不过这可以通过传递this指针解决这个问题。

    综上,我的这个问题可以这个样子解决。

    出问题之前的代码:

    void *thread_rounter(void *)//线程执行函数

    {

       //直接访问类的成员

    }

    exec_task函数中调用:

    pthread_create(&tid,NULL,thread_rounter,NULL);//启动线程执行例程

    修复这个问题的代码:

    static void *thread_rounter(void *tmp)/线程执行函数

    {

      Threadpool *p=(Threadpool *)tmp;

        //通过p指针间接访问类的非静态成员

    }

    exec_task函数中调用:

    pthread_create(&tid,NULL,thread_rounter,(void *)this);//启动线程执行例程

    ----------------------------------------------------------------------------------------------------------------------

    在网上搜索一下还有其他的解决方案,摘录如下,为了以示尊重标明文章来源,感谢原文作者。

    方案二:

    将线程启动函数声明为模板函数。

    摘录自:http://hi.baidu.com/angelevil2006/item/e1806ec30574ff11515058d1

    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的内部。  

    采取这个方案放入我的项目中:

    出问题之前的代码:

    void *thread_rounter(void *)//线程执行函数

    {

       //直接访问类的成员

    }

    exec_task函数中调用:

    pthread_create(&tid,NULL,thread_rounter,NULL);//启动线程执行例程

    修复这个问题的代码:

    添加public成员函数:

    void Run()

    {

      //该函数替换上述thread_rounter的执行代码

    }

    thread_rounter修改为全局模板函数:

    template <typename TYPE, void (TYPE::*Run)() >

    void * thread_rounter(void * param)

    {

        TYPE *p=(TYPE*)param;

        p->Run();

        return NULL;

    }

    exec_task函数中调用:

    pthread_create(&tid,NULL,thread_rounter<Threadpool,&Threadpool::Run>,(void *)this);

    总结:

    解决这个问题的关键在于想方设法使启动函数指针满足void*(*)(void *)类型。

    将启动函数改写成static成员函数适用于可以修改类的源代码的情况。

    而将启动函数写成模板函数还可以适用于没有类的源代码的情况,自己写一个类,公共继承自原类,添加启动函数为模板函数即可。

  • 相关阅读:
    MyBatis Generator去掉生成的注解
    IDEA git修改远程仓库地址
    Spring Boot 集成druid
    解决 SpringBoot 没有主清单属性
    Intellij IDEA 安装lombok及使用详解
    SET FOREIGN_KEY_CHECKS=0;在Mysql中取消外键约束
    @SpringBootApplication
    IDEA 创建git 分支 拉取分支
    Intellij Idea 将java项目打包成jar
    Spring Could Stream 基本用法
  • 原文地址:https://www.cnblogs.com/jiu0821/p/5869600.html
Copyright © 2011-2022 走看看