在C++类中定义线程函数的方法

时间:2021-11-11 07:21:23

最近开始看线程的东西,想把原来的程序优化一下,看到下面的这篇文章,感觉分析得还不错(主要是分析点比较到位,思路很清晰!),在此和大家分享一下。

http://rangercyh.blog.51cto.com/1444712/795759


昨天用C++把我写的一个游戏功能进行了封装,其中涉及到一个小问题,就是我封装的C++类中必须定义2个线程函数,比如像下面这样:

 
 
  1. class A  
  2. {  
  3. public:  
  4.     A();  
  5.     ~A();  
  6.   
  7.     void XXX(void *p);   //此函数为线程回调函数  
  8. };  

其中XXX为线程回调函数,在另一个线程启动函数中需要用_beginthread()这个函数来调用的。但是当我在这么写时:

_beginthread(XXX, 0, NULL);

编译器报错误。。也就是无法编译通过。我仔细想了想,觉得确实也无法编译通过,因为线程函数在编译的时候必须知道函数入口地址才行,而我这么写,XXX的入口地址确实还是未知的。。

所以我想到了两种把未知变为已知的方法,一种是把XXX定义成静态成员函数,如下:

static void XXX(void *p);

另一种是把XXX定义成全局函数。

其实是一个道理,就是为了让_beginthread()知道这个函数的入口地址,全局函数和静态函数都存放在一个地方,在编译时都是已知的。

当我以为一切OK的时候,发现在XXX()函数中又报错了。。

说我使用了不在类域中的成员。其实就是这么个意思:

 
 
  1. class A   
  2. {   
  3. public:   
  4.     A();   
  5.     ~A();   
  6.    
  7.     static void XXX(void *p);   //此函数为线程回调函数 
  8.  
  9.     int a;   //在XXX函数中会进行修改 
  10. };  

其中A的成员变量a会在XXX()函数中进行修改,而在XXX函数中其实是看不到这个成员的。

你也许会问,怎么就看不到呢?我平时就是这么写的啊。比如我在A中定义的其他成员函数就可以直接访问这个a啊。

确实,在类A中其他的一般成员函数是可以访问这个成员变量a的。但是我们很容易忽略了一点,就是在一般成员函数中其实有一个隐藏的参数,就是指向这个类的this指针,我们在成员函数中访问成员变量a,其实是在访问this->a。所以我们的成员函数能够找到这个a,而我们的线程函数却没有传递这个参数,XXX()是用_beginthread()函数来创建的,所以如果我们要给XXX()传递参数,就必须写在_beginthread()的第三个参数中,可以看到我上面写的第三个参数是NULL,所以在XXX()中是无法访问成员变量a的,因为没有this指针。

明白这一点以后就非常容易了,在_beginthread()中把this指针传递给XXX()函数,然后在XXX()函数中把void*类型转换成类A的指针就可以了。如下:

 
 
  1. class A    
  2. {    
  3. public:    
  4.     A();    
  5.     ~A();    
  6.     
  7.     static void XXX(void *p);   //此函数为线程回调函数  
  8.     void start();   //线程启动函数  
  9.     int a;   //在XXX函数中会进行修改  
  10. };  
  11.  
  12. void start() 
  13.     _beginthread(XXX, 0, this); 
  14.  
  15. void XXX(void *p) 
  16.     A *handle = (A *)p; 
  17.     int b = handle->a;