pthread_create使用类中函数指针的…
2013-12-19 20:43
218 查看
原有的程序是利用一台PC机的共享内存来实现两个程序间的通讯的,最近要求改了,要设计2台PC间这两个的程序的通讯,想把通讯部分的程序做成类封装起来。其中,由于要有多线程的部分。就是说,可能在一个线程里读,在另一个线程里写。所以得用到类成员函数的函数指针部分。
为了验证可行性,编写了下面的程序:
class MyThread
{
public:
static int num;
static void * ThreadToRun(void *)
{
printf("Num
is %d/n",num);
return
NULL;
}
};//;不要忘了分号
int MyThread::num = 0;
int main(void)
{
MyThread obj_thread;
pthread_t thread;
pthread_create(&thread,NULL,obj_thread.ThreadToRun,NULL);
...// 其他部分 没有也行
pthread_join(thread,NULL);
return 0;
}
以上是验证程序。
该程序首先验证了,如何使用类的成员函数指针。在线程创建函数里pthread_create(&thread,NULL,obj_thread.ThreadToRun,NULL);我使用了【对象+.+函数名】的方式,而没有使用【类名::函数名】的方式。这是因为,pthread_create函数需要的是一个实际存在的函数的指针。而【类名::函数名】方式并没有满足这个要求(没有对象,就没有成员函数)。而且,使用的函数必须是静态函数,也是这个原因(这个是猜测)。
另外,我还做个验证程序,跟上面的问题没有关系,是关于read,write的阻塞和线程的关系。read,write的阻塞会使当前的进程挂起,直到可以继续读或者写为止。但是如果这个进程里有开了别的线程,read,write的阻塞的阻塞会不会将同一个进程下的其他线程也阻塞掉呢?
我做了个简单的验证试验,在上面的MyThread类的ThreadToRun函数中读出数据,在main函数中(注释的其他部分,没有也行的那部分)加入写入数据。每次向pipe内写入10240个数据,每次在得到用户输入后只读1024个。这样就一定会在主函数中发生阻塞。
如果,读写阻塞会将同一个进程内的所以线程一起阻塞,那么程序就无法正常运行下去(因为读的部分也被挂起了)。而事实正好相反,这就说明,读写阻塞并不会把同一进程下的其他线程都阻塞。
昨天想了一下,和Cypher的想法不谋而合,加一个全局函数,这样可以解决问题,虽然代码看上去有点累赘:
#include
<pthread.h>
class A
{
private:
void*
ThreadFunc(void*);
public:
void
Run();
friend void*
ThreadStub(void*);
//add
a global
function
};
void* ThreadStub(void*
arg)
{
A* pa =
(A*)arg;
pa->
ThreadFunc(NULL);
}
void A::Run()
{
pthread_t
tid;
pthread_create(&tid,
NULL, ThreadStub,
this);
}
另,再请教一下Cypher,你说的"强制取类成员函数的地址是有办法的,你做两次地址转换就可以了",具体可以举例说明一下么.希望以后多多指教,谢谢!
这里的论坛用法不熟悉,刚看到,Sorry。
直接给不同类型的指针赋值肯定是错误的,因为它本身是个变量,但不同变量的地址之间是可以任意转换的。下面给一个例子,为了方便我直接用C的方式转换了(这其实是最强的转换方式):
#include
<iostream>
#include
<cstdio>
class
TestFunc
{
int
iVal;
public:
TestFunc() {
iVal =
100; };
TestFunc(int iPara)
: iVal(iPara)
{};
void
Print(void);
};
typedef void
(TestFunc::*memFuncPtr)(void);
typedef void
(*gFuncPtr)(TestFunc const
*);
void
TestFunc::Print()
{
std::cout <
< "iVal =
" <
< iVal
< <
std::endl;
}
void main()
{
memFuncPtr pmemFunc
=
&(TestFunc::Print);
gFuncPtr pgFunc;
//
直接转换会编译不过去
*(int
*)(&pgFunc) =
*(int *)(&pmemFunc);
//
把其地址转换为int
*
//
指针,然后强制赋值,
//
因为指针则好是四个字节,
//
所以正确。如果你的系统
//
中int不是指针的长度要
//
另想办法,可以用memcpy
//
不能用cout输出,因为这一类型没有重载其operator <
<
// cout
< < pgFunc
< <
endl;
printf( "pmemFunc =
%p pgFunc
= %p\n ",
pmemFunc,
pgFunc);
}
你可以试一试创建一个对象调用pgFunc看结果会怎么样,一般来说会当掉:
TestFunc
objTestFunc(200);
pgFunc(&objTestFunc);
我原来测试这一问题时才可笑,阴差阳错的居然结果正确,高兴了没多久,结果发现任何加或去掉一条语句程序都会死掉。
因为这里访问了this->
iVal,而实际上this指针从寄存器取,所以并不是你传的参数。
为了验证可行性,编写了下面的程序:
class MyThread
{
public:
static int num;
static void * ThreadToRun(void *)
{
printf("Num
is %d/n",num);
return
NULL;
}
};//;不要忘了分号
int MyThread::num = 0;
int main(void)
{
MyThread obj_thread;
pthread_t thread;
pthread_create(&thread,NULL,obj_thread.ThreadToRun,NULL);
...// 其他部分 没有也行
pthread_join(thread,NULL);
return 0;
}
以上是验证程序。
该程序首先验证了,如何使用类的成员函数指针。在线程创建函数里pthread_create(&thread,NULL,obj_thread.ThreadToRun,NULL);我使用了【对象+.+函数名】的方式,而没有使用【类名::函数名】的方式。这是因为,pthread_create函数需要的是一个实际存在的函数的指针。而【类名::函数名】方式并没有满足这个要求(没有对象,就没有成员函数)。而且,使用的函数必须是静态函数,也是这个原因(这个是猜测)。
另外,我还做个验证程序,跟上面的问题没有关系,是关于read,write的阻塞和线程的关系。read,write的阻塞会使当前的进程挂起,直到可以继续读或者写为止。但是如果这个进程里有开了别的线程,read,write的阻塞的阻塞会不会将同一个进程下的其他线程也阻塞掉呢?
我做了个简单的验证试验,在上面的MyThread类的ThreadToRun函数中读出数据,在main函数中(注释的其他部分,没有也行的那部分)加入写入数据。每次向pipe内写入10240个数据,每次在得到用户输入后只读1024个。这样就一定会在主函数中发生阻塞。
如果,读写阻塞会将同一个进程内的所以线程一起阻塞,那么程序就无法正常运行下去(因为读的部分也被挂起了)。而事实正好相反,这就说明,读写阻塞并不会把同一进程下的其他线程都阻塞。
昨天想了一下,和Cypher的想法不谋而合,加一个全局函数,这样可以解决问题,虽然代码看上去有点累赘:
#include
<pthread.h>
class A
{
private:
void*
ThreadFunc(void*);
public:
void
Run();
friend void*
ThreadStub(void*);
//add
a global
function
};
void* ThreadStub(void*
arg)
{
A* pa =
(A*)arg;
pa->
ThreadFunc(NULL);
}
void A::Run()
{
pthread_t
tid;
pthread_create(&tid,
NULL, ThreadStub,
this);
}
另,再请教一下Cypher,你说的"强制取类成员函数的地址是有办法的,你做两次地址转换就可以了",具体可以举例说明一下么.希望以后多多指教,谢谢!
这里的论坛用法不熟悉,刚看到,Sorry。
直接给不同类型的指针赋值肯定是错误的,因为它本身是个变量,但不同变量的地址之间是可以任意转换的。下面给一个例子,为了方便我直接用C的方式转换了(这其实是最强的转换方式):
#include
<iostream>
#include
<cstdio>
class
TestFunc
{
int
iVal;
public:
TestFunc() {
iVal =
100; };
TestFunc(int iPara)
: iVal(iPara)
{};
void
Print(void);
};
typedef void
(TestFunc::*memFuncPtr)(void);
typedef void
(*gFuncPtr)(TestFunc const
*);
void
TestFunc::Print()
{
std::cout <
< "iVal =
" <
< iVal
< <
std::endl;
}
void main()
{
memFuncPtr pmemFunc
=
&(TestFunc::Print);
gFuncPtr pgFunc;
//
直接转换会编译不过去
*(int
*)(&pgFunc) =
*(int *)(&pmemFunc);
//
把其地址转换为int
*
//
指针,然后强制赋值,
//
因为指针则好是四个字节,
//
所以正确。如果你的系统
//
中int不是指针的长度要
//
另想办法,可以用memcpy
//
不能用cout输出,因为这一类型没有重载其operator <
<
// cout
< < pgFunc
< <
endl;
printf( "pmemFunc =
%p pgFunc
= %p\n ",
pmemFunc,
pgFunc);
}
你可以试一试创建一个对象调用pgFunc看结果会怎么样,一般来说会当掉:
TestFunc
objTestFunc(200);
pgFunc(&objTestFunc);
我原来测试这一问题时才可笑,阴差阳错的居然结果正确,高兴了没多久,结果发现任何加或去掉一条语句程序都会死掉。
因为这里访问了this->
iVal,而实际上this指针从寄存器取,所以并不是你传的参数。
相关文章推荐
- pthread_create使用类中函数指针的…
- C++中使用pthread.h头文件报错 - 无法解析的外部符号 __imp__pthread_create,该符号在函数 _main 中被引用
- pthread_create()和pthread_atfork()函数使用时应注意的问题
- 为什么在C++使用pthread_create()的时候,类成员函数做线程的处理函数必须要定义成static类型的?
- 静态成员函数与pthread_create,纯虚函数匹配使用实例
- 解决使用pthread_create函数造成的内存泄露
- pthread_create 函数的安全使用
- pthread_create()函数参数使用心得
- pthread_create()函数使用方法
- 为什么在C++使用pthread_create()的时候,类成员函数做线程的处理函数必须要定义成static类型的?
- 解决使用pthread_create函数造成的内存泄露
- 静态成员函数与pthread_create,纯虚函数匹配使用实例
- C++使用线程函数pthread_create时,调用的成员函数要定义为静态成员函数
- C++中使用pthread.h头文件报错 - 无法解析的外部符号 __imp__pthread_create,该符号在函数 _main 中被引用
- 避免使用不当pthread_create函数造成内存泄露
- C++中使用pthread.h头文件报错 - 无法解析的外部符号 __imp__pthread_create,该符号在函数 _main 中被引用
- 解决使用pthread_create函数造成的内存泄露
- C++学习14:使用typedef定义函数指针类型
- c++11 条款22:当使用Pimpl(指向实现的指针)时,在实现文件里定义特定的成员函数
- pthread_join函数介绍和使用实例