类成员函数作为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成员函数适用于可以修改类的源代码的情况。
而将启动函数写成模板函数还可以适用于没有类的源代码的情况,自己写一个类,公共继承自原类,添加启动函数为模板函数即可。
类成员函数作为pthread_create函数参数的更多相关文章
- static类成员(变量和函数)
0. 使用背景 对于特定类类型的全体对象而言,访问一个全局对象有时是必要的.也许,在程序的任意点需要统计已创建的特定类类型对象的数量:或者,全局对象可能是指向类的错误处理例程的一个指针:或者,它是指向 ...
- [转载] C++ 类中的类成员变量怎么调用带参数的构造函数来初始化?
#include "stdafx.h" class A { public: A(){ax = ;}; A(int a){ax = a;}; int ax; }; class B { ...
- C++类成员存储大小
1.对象分布图 2.解析 每个类的大小只有其成员变量大小,其中包括:类成员属性,虚函数指针: 而其他没有如:静态变量[静态区],普通函数.静态函数[代码区] 3.总结 类对象的sizeof只包含成员变 ...
- C++中 线程函数为静态函数 及 类成员函数作为回调函数
线程函数为静态函数: 线程控制函数和是不是静态函数没关系,静态函数是在构造中分配的地址空间,只有在析构时才释放也就是全局的东西,不管线程是否运行,静态函数的地址是不变的,并不在线程堆栈中static只 ...
- 重载运算符:类成员函数or友元函数
类成员函数: bool operator ==(const point &a)const { return x==a.x; } 友元函数: friend bool operator ==(co ...
- C++类成员函数的重载、覆盖和隐藏区别?
C++类成员函数的重载.覆盖和隐藏区别? a.成员函数被重载的特征:(1)相同的范围(在同一个类中):(2)函数名字相同:(3)参数不同:(4)virtual 关键字可有可无.b.覆盖是指派生类函数覆 ...
- C++学习46 getline()函数读入一行字符 一些与输入有关的istream类成员函数
getline函数的作用是从输入流中读取一行字符,其用法与带3个参数的get函数类似.即 cin.getline(字符数组(或字符指针), 字符个数n, 终止标志字符) [例13.7] 用get ...
- 类成员函数指针 ->*语法剖析
在cocos2d-x中,经常会出现这样的调用,如 ->*,这个是什么意思呢,如下面得这个例子: , 其实这是对类的成员函数指针的调用,在cocos2dx中,这种形式多用于回调函数的调用.如我们经 ...
- C++类成员函数的 重载、覆盖和隐藏区别
重载:成员函数被重载的特征: (1)相同的范围(在同一个类中): (2)函数名字相同: (3)参数不同: (4)virtual 关键字可有可无. #include <iostream> u ...
随机推荐
- bootstrap学习笔记<四>(table表格)
表格 bootstrap为table表格定制多个常用样式:基本样式,隔行变色样式,带边框样式,荧光棒样式,紧凑样式,响应样式. ☑ .table:基础表格 ☑ .table-striped:斑马线 ...
- 线程高级应用-心得8-java5线程并发库中同步集合Collections工具类的应用及案例分析
1. HashSet与HashMap的联系与区别? 区别:前者是单列后者是双列,就是hashmap有键有值,hashset只有键: 联系:HashSet的底层就是HashMap,可以参考HashSe ...
- css 的小细节,小总结
CSS的一些零碎总结 1.CSS 伪元素用于向某些选择器设置特殊效果(用来当作一个东西的,跟一个元素差不多,但不是元素). ① :frist-line伪元素:用于向文本首行设置特殊样式,但是只能用于块 ...
- Android中view动画
[1]透明 //点击按钮 实现iv 透明的效果 动画 public void click1(View v) { //1.0意味着着完全不透明 0.0意味着完全透明 AlphaAnimation aa ...
- 【Android界面实现】FragmentPagerAdapter与FragmentStatePagerAdapter使用详解与区别
转载请注明出处: http://blog.csdn.net/zhaokaiqiang1992 FragmentPagerAdapter是android-support-v4支持包里面出现的一个新的适配 ...
- JQuery $()后面的括号里的内容什么时候加引号,什么时候不加
一.如果是已经声明存在的变量或者对象,就不用加引号. 比如var name=document.getElementById("name"); $(name)或者$(this). 二 ...
- 转:C++中Static作用和使用方法
转自:http://blog.csdn.net/artechtor/article/details/2312766 1.什么是static? static 是C++中很常用的修饰符,它被用 ...
- 无法找到脚本*.VBS的脚本引擎解决办法
当你在运行一些基于VBS脚本语言的文件时,系统可能报错.这时候可能是你的VBS脚本服务在注册表中出错了,原因可能是卸载或安装一些代码不规范的程序引起的.这里给出无法找到脚本引擎"vbscri ...
- <mvc:annotation-driven />
<mvc:annotation-driven/>相当于注册了DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter两个 ...
- Loadrunner基础:Loadrunner Controller基本概念和使用
Loadrnner Controller 介绍 当Vuser脚本开发完成以后,可以使用Controller将这个执行脚本的用户从单用户转化为多用户,从而模拟大量用户的操作,形成负载(多用户单循环,多用 ...