`
isiqi
  • 浏览: 16054023 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

深入浅出Win32多线程程序设计之二:线程控制

阅读更多

深入浅出Win32多线程程序设计之线程控制

<!--广告-->
<!-- Please check block file -->
<!-- Please check block file -->
  WIN32线程控制主要实现线程的创建、终止、挂起和恢复等操作,这些操作都依赖于WIN32提供的一组API和具体编译器的C运行时库函数。

  1.线程函数

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

UINT ThreadFunction(LPVOID pParam)
{
 //线程处理代码
 return0;
}

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

while(1)
{
 WaitForSingleObject(…,…);//或WaitForMultipleObjects(…)
 //Do something
}

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

#include "windows.h"
#include <process.h>
class ExampleTask
{
 public:
  void taskmain(LPVOID param);
  void StartTask();
};
void ExampleTask::taskmain(LPVOID param)
{}

void ExampleTask::StartTask()
{
 _beginthread(taskmain,0,NULL);
}

int main(int argc, char* argv[])
{
 ExampleTask realTimeTask;
 realTimeTask.StartTask();
 return 0;
}

  程序编译时出现如下错误:

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

  再看下列程序:

#include "windows.h"
#include <process.h>
class ExampleTask
{
 public:
  void taskmain(LPVOID param);
};

void ExampleTask::taskmain(LPVOID param)
{}

int main(int argc, char* argv[])
{
 ExampleTask realTimeTask;
 _beginthread(ExampleTask::taskmain,0,NULL);
 return 0;
}

  程序编译时会出错:

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指针;

  我们将上述二个程序改变为:

#include "windows.h"
#include <process.h>
class ExampleTask
{
 public:
  void static taskmain(LPVOID param);
  void StartTask();
};

void ExampleTask::taskmain(LPVOID param)
{}

void ExampleTask::StartTask()
{
 _beginthread(taskmain,0,NULL);
}

int main(int argc, char* argv[])
{
 ExampleTask realTimeTask;
 realTimeTask.StartTask();
 return 0;
}

#include "windows.h"
#include <process.h>
class ExampleTask
{
 public:
  void static taskmain(LPVOID param);
};

void ExampleTask::taskmain(LPVOID param)
{}

int main(int argc, char* argv[])
{
 _beginthread(ExampleTask::taskmain,0,NULL);
 return 0;
}

  均编译通过。

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

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

  我们将程序修改为:

#include "windows.h"
#include <process.h>
class ExampleTask
{
 public:
  friend void taskmain(LPVOID param);
  void StartTask();
};

void taskmain(LPVOID param)
{
 ExampleTask * pTaskMain = (ExampleTask *) param;
 //通过pTaskMain指针引用
}

void ExampleTask::StartTask()
{
 _beginthread(taskmain,0,this);
}
int main(int argc, char* argv[])
{
 ExampleTask realTimeTask;
 realTimeTask.StartTask();
 return 0;
}

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

2.创建线程

  进程的主线程由操作系统自动生成,Win32提供了CreateThread API来完成用户线程的创建,该API的原型为:

HANDLE CreateThread(
 LPSECURITY_ATTRIBUTES lpThreadAttributes,//Pointer to a SECURITY_ATTRIBUTES structure
 SIZE_T dwStackSize, //Initial size of the stack, in bytes.
 LPTHREAD_START_ROUTINE lpStartAddress,
 LPVOID lpParameter, //Pointer to a variable to be passed to the thread
 DWORD dwCreationFlags, //Flags that control the creation of the thread
 LPDWORD lpThreadId //Pointer to a variable that receives the thread identifier
);

  如果使用C/C++语言编写多线程应用程序,一定不能使用操作系统提供的CreateThread API,而应该使用C/C++运行时库中的_beginthread(或_beginthreadex),其函数原型为:

uintptr_t _beginthread(
 void( __cdecl *start_address )( void * ), //Start address of routine that begins execution of new thread
 unsigned stack_size, //Stack size for new thread or 0.
 void *arglist //Argument list to be passed to new thread or NULL
);
uintptr_t _beginthreadex(
 void *security,//Pointer to a SECURITY_ATTRIBUTES structure
 unsigned stack_size,
 unsigned ( __stdcall *start_address )( void * ),
 void *arglist,
 unsigned initflag,//Initial state of new thread (0 for running or CREATE_SUSPENDED for suspended);
 unsigned *thrdaddr
);

  _beginthread函数与Win32 API 中的CreateThread函数类似,但有如下差异:

  (1)通过_beginthread函数我们可以利用其参数列表arglist将多个参数传递到线程;

  (2)_beginthread 函数初始化某些 C 运行时库变量,在线程中若需要使用 C 运行时库。

  3.终止线程

  线程的终止有如下四种方式:

  (1)线程函数返回;

  (2)线程自身调用ExitThread 函数即终止自己,其原型为:

VOID ExitThread(UINT fuExitCode );

  它将参数fuExitCode设置为线程的退出码。

  注意:如果使用C/C++编写代码,我们应该使用C/C++运行时库函数_endthread (_endthreadex)终止线程,决不能使用ExitThread!
_endthread 函数对于线程内的条件终止很有用。例如,专门用于通信处理的线程若无法获取对通信端口的控制,则会退出。

  (3)同一进程或其他进程的线程调用TerminateThread函数,其原型为:

BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);

  该函数用来结束由hThread参数指定的线程,并把dwExitCode设成该线程的退出码。当某个线程不再响应时,我们可以用其他线程调用该函数来终止这个不响应的线程。

  (4)包含线程的进程终止。

  最好使用第1种方式终止线程,第2~4种方式都不宜采用。

  4.挂起与恢复线程

  当我们创建线程的时候,如果给其传入CREATE_SUSPENDED标志,则该线程创建后被挂起,我们应使用ResumeThread恢复它:

DWORD ResumeThread(HANDLE hThread);

  如果ResumeThread函数运行成功,它将返回线程的前一个暂停计数,否则返回0x FFFFFFFF。

  对于没有被挂起的线程,程序员可以调用SuspendThread函数强行挂起之:

DWORD SuspendThread(HANDLE hThread);

  一个线程可以被挂起多次。线程可以自行暂停运行,但是不能自行恢复运行。如果一个线程被挂起n次,则该线程也必须被恢复n次才可能得以执行。

转自天极网,原文链接:http://soft.yesky.com/lesson/36/2280536.shtml
分享到:
评论

相关推荐

    深入浅出Win32多线程程序设计.pdf

    深入浅出Win32多线程程序设计.pdf 讲述多线程编程

    深入浅出Win32多线程程序设计之线程控制

    深入浅出Win32多线程程序设计之线程控制深入浅出Win32多线程程序设计之线程控制深入浅出Win32多线程程序设计之线程控制深入浅出Win32多线程程序设计之线程控制

    深入浅出Win32多线程程序设计[收集].pdf

    深入浅出Win32多线程程序设计[收集].pdf

    深入浅出Win32多线程程序设计之综合实例

    想深入学习多线程的一定要看看的哦

    深入浅出Win32多线程程序设计之线程通信.doc

    深入浅出Win32多线程程序设计之线程通信

    深入浅出Win32多线程程序设计之基本概念

    深入浅出Win32多线程程序设计之基本概念,欢迎下载

    深入浅出Win32多线程程序设计之线程通信[归类].pdf

    深入浅出Win32多线程程序设计之线程通信[归类].pdf

    深入浅出Win32多线程程序设计

    理解多线程及其同步、互斥等通信方式是理解现代操作系统的关键一环,当我们精通了Win32多线程程序设计后,理解和学习其它操作系统的多任务控制也非常容易。许多程序员从来没有学习过嵌入式系统领域著名的操作系统...

    win32多线程编程

    深入浅出Win32多线程程序设计之基本概念 2005-12-14 09:48作者:宋宝华出处:天极开发责任编辑:方舟  引言  从单进程单线程到多进程多线程是操作系统发展的一种必然趋势,当年的DOS系统属于单任务操作系统,最...

    Windows多线程

    《Windows多线程编程技术与实例》-郝文化-源代码 VC多线程编程.CHM Win32多线程.pdf Win32多线程程序设计(完美版).pdf 多线程编程基础.pdf 深入浅出Win32多线程程序设计.pdf

    深入vc、win32资料

    Visual+C++动态链接库(Dll)编程.chm、深入浅出VC++串口编程.pdf、深入浅出Win32多线程程序设计

    深入浅出 MFC (第二版) 高清晰

    目录 · · · · · · 第一篇 勿在浮砂筑高台 第一章 Win32 程序基本概念 ...第十四章 MFC 多线程程序设计 第十五章 站在众人的肩膀――使用Components & ActiveX Controls 第五篇 附录 · · · · · ·

    深入浅出MFC-简体版(2)PDF

    《深入浅出MFC》2/e 简体版 目录 第0章 你一定要知道(导读) 这本书适合谁 你需要什么技术基础 你需要什么软硬件环境 让我们使用同一种语言 本书符号习惯 本书例程的取得 范例程序说明 与前版本之差异 如何联络作者...

    深入浅出MFC

    早已听说本书是一本不可多得的好书,以前没认真也没坚持看完,至今重新慢慢捡起,才发现本书非常不错,跟大家分享一下。...第14章 mfc多线程程序设计 第16章 站上众人的肩膀——使用components&activex; controls

    深入浅出MFC 2e

    深入浅出MFC(第二版) 目录 第0章 你一定要知道(导读) 这本书适合谁 你需要什么技术基础 你需要什么软硬件环境 让我们使用同一种语言 本书符号习惯 本书例程的取得 范例程序说明 与前版本之差异 如何联络作者 第...

    多线程编程初学者指南

     理解多线程及其同步、互斥等通信方式是理解现代操作系统的关键一环,当我们精通了Win32多线程程序设计后,理解和学习其它操作系统的多任务控制也非常容易。因此,学习Win32多线程不仅对理解Win32本身有重要意义,...

    MFC深入浅出带目录完整版(李久进chm版)

    本书的中心就是深入浅出地解析MFC类库,分析怎么使用MFC类库以及MFC类库的内部实现,揭开MFC复杂、深奥的面纱,让读者对MFC有一个全面、透彻、清晰的理解。关于MFC的核心实现,主要有以下几个方面。 首先,MFC采用...

Global site tag (gtag.js) - Google Analytics