成员函数或友元函数做为线程函数

http://www.buguw.com/?p=187
WIN32线程控制主要实现线程的创建、终止、挂起和恢复等操作,这些操作都依赖于WIN32提供的一组API和具体编译器的C运行时库函数。

1.线程函数
  在启动一个线程之前,必须为线程编写一个全局的线程函数,这个线程函数接受一个32位的LPVOID作为参数,返回一个UINT,线程函数的结构为:

  1. UINT ThreadFunction(LPVOID pParam)
  2. {
  3.  //线程处理代码
  4.  return0;
  5. }

复制代码

  在线程处理代码部分通常包括一个死循环,该循环中先等待某事情的发生,再处理相关的工作:

  1. while(1)
  2. {
  3.  WaitForSingleObject(…,…);//或WaitForMultipleObjects(…)
  4.  //Do something
  5. }

复制代码

  一般来说,C++的类成员函数不能作为线程函数。这是因为在类中定义的成员函数,编译器会给其加上this指针。请看下列程序:

  1. #include "windows.h"
  2. #include
  3. class ExampleTask 

  4.  public: 
  5.   void taskmain(LPVOID param); 
  6.   void StartTask(); 
  7. }; 
  8. void ExampleTask::taskmain(LPVOID param) 
  9. {} 
  10. void ExampleTask::StartTask() 

  11.  _beginthread(taskmain,0,NULL);

  12. int main(int argc, char* argv[])
  13. {
  14.  ExampleTask realTimeTask;
  15.  realTimeTask.StartTask();
  16.  return 0;
  17. }

复制代码

  程序编译时出现如下错误:
error C2664: '_beginthread' : cannot convert parameter 1 from 'void (void *)' to 'void (__cdecl *)(void *)'
None of the functions with this name in scope match the target type

  再看下列程序:

  1. #include "windows.h"
  2. #include
  3. class ExampleTask 

  4.  public: 
  5.   void taskmain(LPVOID param); 
  6. }; 
  7. void ExampleTask::taskmain(LPVOID param) 
  8. {} 
  9. int main(int argc, char* argv[])
  10. {
  11.  ExampleTask realTimeTask;
  12.  _beginthread(ExampleTask::taskmain,0,NULL);
  13.  return 0;
  14. }

复制代码

  程序编译时会出错:
error C2664: '_beginthread' : cannot convert parameter 1 from 'void (void *)' to 'void (__cdecl *)(void *)'
None of the functions with this name in scope match the target type

  如果一定要以类成员函数作为线程函数,通常有如下解决方案:

  (1)将该成员函数声明为static类型,去掉this指针;
  我们将上述二个程序改变为:

  1. #include"windows.h"
  2. #include
  3. class ExampleTask 

  4.  public: 
  5.   void static taskmain(LPVOID param); 
  6.   void StartTask(); 
  7. }; 
  8. void ExampleTask::taskmain(LPVOID param) 
  9. {} 
  10. void ExampleTask::StartTask() 

  11.  _beginthread(taskmain,0,NULL);

  12. int main(int argc, char* argv[])
  13. {
  14.  ExampleTask realTimeTask;
  15.  realTimeTask.StartTask();
  16.  return 0;
  17. }

复制代码

  1. #include "windows.h"
  2. #include
  3. class ExampleTask 

  4.  public: 
  5.   void static taskmain(LPVOID param); 
  6. }; 
  7. void ExampleTask::taskmain(LPVOID param) 
  8. {} 
  9. int main(int argc, char* argv[])
  10. {
  11.  _beginthread(ExampleTask::taskmain,0,NULL);
  12.  return 0;
  13. }

复制代码

  均编译通过。

  将成员函数声明为静态虽然可以解决作为线程函数的问题,但是它带来了新的问题,那就是static成员函数只能访问static成员。解决此问题的一种途径是可以在调用类静态成员函数(线程函数)时将this指针作为参数传入,并在改线程函数中用强制类型转换将this转换成指向该类的指针,通过该指针访问非静态成员。

  (2)不定义类成员函数为线程函数,而将线程函数定义为类的友元函数。
这样,线程函数也可以有类成员函数同等的权限;
 
  我们将程序修改为:

  1. #include “windows.h"
  2. #include
  3. class ExampleTask 

  4.  public: 
  5.   friend void taskmain(LPVOID param); 
  6.   void StartTask(); 
  7. }; 
  8. void taskmain(LPVOID param) 

  9.  ExampleTask * pTaskMain = (ExampleTask *) param; 
  10.  //通过pTaskMain指针引用 

  11. void ExampleTask::StartTask() 

  12.  _beginthread(taskmain,0,this);
  13. }
  14. int main(int argc, char* argv[])
  15. {
  16.  ExampleTask realTimeTask;
  17.  realTimeTask.StartTask();
  18.  return 0;
  19. }

复制代码

(3)可以对非静态成员函数实现回调,并访问非静态成员,此法涉及到一些高级技巧,在此不再详述。


-----------------------------------------------------------------------------
linux代码
线程函数定义为类的友元函数

  1. #include <iostream>
  2. #include <stdio.h>
  3. #include <pthread.h>
  4. #include <errno.h>

  5. using namespace std;

  6. class ExampleTask
  7. {
  8.     public:
  9.         friend void* taskmain(void *param);
  10.         void startTask();
  11.         void done();
  12. };

  13. /* 线程函数 */
  14. void* taskmain(void *param)
  15. {
  16.     printf("-- %s enter\n", __func__);
  17.     ExampleTask *pTaskMain = (ExampleTask*)param;
  18.     pTaskMain->done();
  19.     printf("-- %s leave\n", __func__);
  20. }

  21. void ExampleTask::startTask()
  22. {
  23.     printf("%s enter\n", __func__);
  24.     pthread_t pthread;
  25.     int ret;

  26.     ret = pthread_create(&pthread, NULL, taskmain, this);
  27.     if ( ret != 0 )
  28.     {
  29.         perror("pthread_create");
  30.     }

  31.     printf("wait for pthread exit\n", __func__);
  32.     pthread_join(pthread, NULL);

  33.     printf("%s leave\n", __func__);
  34. }

  35. void ExampleTask::done()
  36. {
  37.     cout<<"pthread use ExampleTask method!"<<endl;
  38. }


  39. int main()
  40. {
  41.     ExampleTask t;
  42.     t.startTask();
  43.     return 0;
  44. }

<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
阅读(235) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页