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

  1. template <typename TYPE, void (TYPE::*_RunThread)() >
  2. void* _thread_t(void* param)//线程启动函数,声明为模板函数
  3. {
  4. TYPE* This = (TYPE*)param;
  5. This->_RunThread();
  6. return NULL;
  7. }
  8.  
  9. class MyClass
  10. {
  11. public:
  12. MyClass();
  13. void _RunThread();
  14.  
  15. private:
  16. pthread_t tid;
  17. };
  18.  
  19. void MyClass::_RunThread()
  20. {
  21. this->DoSomeThing();
  22. }
  23.  
  24. MyClass::MyClass()
  25. {
  26. pthread_create(&tid, NULL, _thread_t<MyClass, &MyClass::_RunThread>, this);
  27. }
  28.  
  29. //函数模版不单可以替换类型本身,还能替换类型的成员函数。
  30. //注意: 1、名称只能是_RunThread,不能在指定模版参数的时候修改;
  31. // 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成员函数适用于可以修改类的源代码的情况。

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

类成员函数作为pthread_create函数参数的更多相关文章

  1. static类成员(变量和函数)

    0. 使用背景 对于特定类类型的全体对象而言,访问一个全局对象有时是必要的.也许,在程序的任意点需要统计已创建的特定类类型对象的数量:或者,全局对象可能是指向类的错误处理例程的一个指针:或者,它是指向 ...

  2. [转载] C++ 类中的类成员变量怎么调用带参数的构造函数来初始化?

    #include "stdafx.h" class A { public: A(){ax = ;}; A(int a){ax = a;}; int ax; }; class B { ...

  3. C++类成员存储大小

    1.对象分布图 2.解析 每个类的大小只有其成员变量大小,其中包括:类成员属性,虚函数指针: 而其他没有如:静态变量[静态区],普通函数.静态函数[代码区] 3.总结 类对象的sizeof只包含成员变 ...

  4. C++中 线程函数为静态函数 及 类成员函数作为回调函数

    线程函数为静态函数: 线程控制函数和是不是静态函数没关系,静态函数是在构造中分配的地址空间,只有在析构时才释放也就是全局的东西,不管线程是否运行,静态函数的地址是不变的,并不在线程堆栈中static只 ...

  5. 重载运算符:类成员函数or友元函数

    类成员函数: bool operator ==(const point &a)const { return x==a.x; } 友元函数: friend bool operator ==(co ...

  6. C++类成员函数的重载、覆盖和隐藏区别?

    C++类成员函数的重载.覆盖和隐藏区别? a.成员函数被重载的特征:(1)相同的范围(在同一个类中):(2)函数名字相同:(3)参数不同:(4)virtual 关键字可有可无.b.覆盖是指派生类函数覆 ...

  7. C++学习46 getline()函数读入一行字符 一些与输入有关的istream类成员函数

    getline函数的作用是从输入流中读取一行字符,其用法与带3个参数的get函数类似.即    cin.getline(字符数组(或字符指针), 字符个数n, 终止标志字符) [例13.7] 用get ...

  8. 类成员函数指针 ->*语法剖析

    在cocos2d-x中,经常会出现这样的调用,如 ->*,这个是什么意思呢,如下面得这个例子: , 其实这是对类的成员函数指针的调用,在cocos2dx中,这种形式多用于回调函数的调用.如我们经 ...

  9. C++类成员函数的 重载、覆盖和隐藏区别

    重载:成员函数被重载的特征: (1)相同的范围(在同一个类中): (2)函数名字相同: (3)参数不同: (4)virtual 关键字可有可无. #include <iostream> u ...

随机推荐

  1. c#获取url请求的返回值(转)

    有两种方式获取. 方法一: /// <summary> /// 获取url的返回值 /// </summary> /// <param name="url&qu ...

  2. 我想有个梦想(I want have a dream)

    成东青说过:梦想是什么,梦想就是你坚持就觉得是幸福东西. 多好啊,有梦想,想想就觉得幸福的.也许你会觉得有点做作,但我真觉得是这样.没有梦想就像一个没有了灵魂的躯壳,整天浑浑噩噩,整天麻木的上班下班, ...

  3. mysql 查询开销 sending data

    1.执行一个查询,发现时间开销都在sending data,为什么?2.sending data容易误导,让人以为只是发送数据给客户端,实际上sending data包含两个过程:读取数据并处理,发送 ...

  4. java 嵌套类 简记

    嵌套类包括:1)静态嵌套类  (static 修饰符) 2)非静态嵌套类(又叫内部类) 其中内部类又可分为三种: 其一.在一个类(外部类)中直接定义的内部类: 其二.在一个方法(外部类的方法)中定义的 ...

  5. mysql 批处理文件--- 创建 用户 以及 导入数据

    在window下,通过批处理文件(.bat),进行开启MYSQL服务,导入数据文件(.sql) 1)新建一个txt文件,写入以下内容 rem 启动mysql56服务  mysql56是我的mysql服 ...

  6. cocoapods ,错误大全

    出现这种警告 Your Podfile has had smart quotes sanitised. To avoid issues in the future, you should not us ...

  7. vsphere vcenter 添加域管理员

    选择 vcenter server  管理权限

  8. centos7 安装mariaDB 以及 phpmyadmin的安装

    centos7 安装mariaDB 以及 phpmyadmin的安装 一:安装mariadb, mariadb 是 mysql 的一个分支,基本和mysql一样的 1. yum -y install ...

  9. java的System.getProperty()方法可以获取的值

    java.version Java 运行时环境版本 java.vendor Java 运行时环境供应商 java.vendor.url Java 供应商的 URL java.home Java 安装目 ...

  10. 35 个免费创新的响应式 HTML5 模板

    HTML5 和响应式都是 Web 开发领域中的热门技术,本文向你推荐 35 个免费的响应式 HTML5 模板,将两种技术完美结合. Mori responsive HTML5 Template Res ...