现在的位置: 首页 > 综合 > 正文

成员函数做为线程函数

2013年12月10日 ⁄ 综合 ⁄ 共 2527字 ⁄ 字号 评论关闭

网上找来的资料如下:

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 <process.h>
  3. class ExampleTask
  4. {
  5.  public:
  6.   void taskmain(LPVOID param);
  7.   void StartTask();
  8. };
  9. void ExampleTask::taskmain(LPVOID param)
  10. {}
  11. void ExampleTask::StartTask()
  12. {
  13.  _beginthread(taskmain,0,NULL);
  14. }
  15. int main(int argc, char* argv[])
  16. {
  17.  ExampleTask realTimeTask;
  18.  realTimeTask.StartTask();
  19.  return 0;
  20. }

复制代码

  程序编译时出现如下错误:
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 <process.h>
  3. class ExampleTask
  4. {
  5.  public:
  6.   void taskmain(LPVOID param);
  7. };
  8. void ExampleTask::taskmain(LPVOID param)
  9. {}
  10. int main(int argc, char* argv[])
  11. {
  12.  ExampleTask realTimeTask;
  13.  _beginthread(ExampleTask::taskmain,0,NULL);
  14.  return 0;
  15. }

复制代码

  程序编译时会出错:
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<process.h>
  3. class ExampleTask
  4. {
  5.  public:
  6.   void static taskmain(LPVOID param);
  7.   void StartTask();
  8. };
  9. void ExampleTask::taskmain(LPVOID param)
  10. {}
  11. void ExampleTask::StartTask()
  12. {
  13.  _beginthread(taskmain,0,NULL);
  14. }
  15. int main(int argc, char* argv[])
  16. {
  17.  ExampleTask realTimeTask;
  18.  realTimeTask.StartTask();
  19.  return 0;
  20. }

复制代码

  1. #include "windows.h"
  2. #include <process.h>
  3. class ExampleTask
  4. {
  5.  public:
  6.   void static taskmain(LPVOID param);
  7. };
  8. void ExampleTask::taskmain(LPVOID param)
  9. {}
  10. int main(int argc, char* argv[])
  11. {
  12.  _beginthread(ExampleTask::taskmain,0,NULL);
  13.  return 0;
  14. }

复制代码

  均编译通过。

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

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

  我们将程序修改为:

  1. #include “windows.h"
  2. #include <process.h>
  3. class ExampleTask
  4. {
  5.  public:
  6.   friend void taskmain(LPVOID param);
  7.   void StartTask();
  8. };
  9. void taskmain(LPVOID param)
  10. {
  11.  ExampleTask * pTaskMain = (ExampleTask *) param;
  12.  //通过pTaskMain指针引用
  13. }
  14. void ExampleTask::StartTask()
  15. {
  16.  _beginthread(taskmain,0,this);
  17. }
  18. int main(int argc, char* argv[])
  19. {
  20.  ExampleTask realTimeTask;
  21.  realTimeTask.StartTask();
  22.  return 0;
  23. }

复制代码

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

抱歉!评论已关闭.