您的位置:首页 > 其它

pthread_create使用类中函数指针的…

2013-12-19 20:43 239 查看
原有的程序是利用一台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指针从寄存器取,所以并不是你传的参数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐