Windows下多线程编程技术及其实现

转载 2007年09月21日 16:16:00
Windows下多线程编程技术及其实现

  本文首先讨论16位Windows下不具备的线程的概念,然后着重讲述在32位Windows 95环境下多线程的编程技术,最后给出利用该技术的一个实例,即基于Windows95下TCP/IP的可视电话的实现。

  一、问题的提出

  作者最近在开发基于Internet网上的可视电话过程中,碰到了这样一个问题。在基于Internet网上的可视电话系统中,同时要进行语音采集、语音编解码、图象采集、图象编解码、语音和图象 码流的传输, 所有的这些事情,都要并行处理。特别是语音信号,如果进行图象编解码时间过长,语音信号得不到服务,通话就有间断,如果图象或语音处理时间过长,而不能及时的传输码流数据,通信同样也会中断。这样就要求我们实现一种并行编程,在只有一个CPU的机器上,也就是要将该CPU时间按照一定的优先准则分配给各个事件,定期处理某一事件而不会在某一事件处理过长,在32位Windows95或WindowsNT下,我们可以用多线程的编程技术来实现这种并行编程。实际上这种并行编程在很多场合下都是必须的。例如,在FileManager拷贝文件时,它显示一个对话框, 列出源文件和目标文件的名称,并在对话框中包含了一个Cancel按钮。如果在文件拷贝过程中,点中Cancel按钮,就会终止拷贝。

  在16位Windows中,实现这类功能需要在FileCopy循环内部周期性地调用PeekMessage函数。如果正在读一个很大的数据块,则只有当这个块读完以后才能响应这个按钮动作,如果从软盘读文件,则要花费好几秒的时间,由于机器反应太迟钝,你会频繁地点中这个按钮,以为系统不知道你想终止这个操作。如果把FileCopy指令放入另外一个线程,你就不需要在代码中放一大堆PeekMessage函数,处理 用户界面的线程将与它分开操作,这样,点中Cancel按钮后会立即得到响应。同样的道理,在应用程序中创建一个单独线程来处理所有打印任务也是很有用的,这样,用户可以在打印处理时继续使用应用程序。

  二、线程的概念

  为了了解线程的概念,我们必须先讨论一下进程的概念。

  一个进程通常定义为程序的一个实例。在Win32中, 进程占据4GB的地址空间。与它们在MS-DOS和16位Windows操作系统中不同, Win32进程是没有活力的。这就是说,一个Win32进程并不执行什么指令,它只是占据着4GB的地址空间,此空间中有应用程序EXE文件的 代码和数据。EXE需要的任意DLL也将它们的代码和数据装入到进程的地址空间。除了地址空间,进程还占有某些资源,比如文件、动态内存分配和线程。当进程终止时,在它生命期中创建的各种资源将被清除。

  但是进程是没有活力的,它只是一个静态的概念。为了让进程完成一些工作,进程必须至少占有一个线程,所以线程是描述进程内的执行,正是线程负责执行包含在进程的地址空间中的代码。实际上,单个进程可以包含几个线程, 它们可以同时执行进程的地址空间中的代码。为了做到这一点,每个线程有自己的一组CPU寄存器和堆栈。

  每个进程至少有一个线程在执行其地址空间中的代码,如果没有线程执行进程 地址空间中的代码, 进程也就没有继续存在的理由,系统将自动清除进程及其地址空间。为了运行所有这些线程,操作系统为每个独立线程安排一些CPU 时间,操作系统以轮转方式向线程提供时间片,这就给人一种假象,好象这些线程都在同时运行。创建一个Win32进程时,它的第一个线程称为主线程,它 由系统自动生成,然后可由这个主线程生成额外的线程,这些线程,又可生成更多的线程。

  三、线程的编程技术

  1、编写线程函数

  所有线程必须从一个指定的函 数开始执行,该函数称为线程函数,它必须具有下列原型:

DWORD WINAPIYourThreadFunc(LPVOIDlpvThreadParm);

  该函数输入一个LPVOID型的参数,可以是一个DWORD型的整数,也可以是一个指向一个缓冲区的指针, 返回一个DWORD型的值。象WinMain函数一样,这个函数并不由操作系统调用, 操作系统调用包含在KERNEL32.DLL中的非C运行时的一个内部函数,如StartOfThread,然后由StartOfThread函数建立起一个异常处理框架后,调用我们的函数。

  2、创建一个线程

  一个进程的主线程是由操作系统自动生成,如果你要让一个主线程创建额外的线程,你可以调用来CreateThread完成。

  HANDLE  CreateThread(LPSECURITY_ATTRIBUTES lpsa,DWORDcbstack,LPTHREAD_START_ROUTINElpStartAddr,
LPVOID lpvThreadParm,DWORDfdwCreate,LPDWORDlpIDThread);

  其中lpsa参数为一个指向SECURITY_ATTRIBUTES结构的指针。如果想让对象为缺省安全属性的话,可以传一个NULL,如果想让任一个子进程都可继承一个该线程对象句柄,必须指定一个SECURITY_ATTRIBUTES结构,其中bInheritHandle成员初始化为TRUE。参数cbstack表示线程为自己所用堆栈分配的地址空间大小,0表示采用系统缺省值。

  参数lpStartAddr用来表示新线程开始执行时代码所在函数的地址,即为线程函数。lpvThreadParm为传入线程函数的参数,fdwCreate参数指定控制线程创建的附加标志,可以取两种值。如果该参数为0,线程就会立即开始执行,如果该参数为CREATE_SUSPENDED,则系统产生线程后,初始化CPU,登记CONTEXT结构的成员,准备好执行该线程函数中的第一条指令,但并不马上执行,而是挂起该线程。最后一个参数lpIDThread 是一个DWORD类型地址,返回赋给该新线程的ID值。

  3、终止线程

  如果某线程调用了ExitThread 函数,就可以终止自己。

                VOID  ExitThread(UINTfuExitCode );

  这个函数为调用该函数的线程设置了退出码fuExitCode后, 就终止该线程。调用TerminateThread函数亦可终止线程。

BOOLTerminateThread(HANDLE hThread,DWORDdwExitCode);

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

  4、设定线程的相对优先级

  当一个线程被首次创建时,它的优先级等同于它所属进程的优先级。在单个进程内可以通过调用SetThreadPriority函数改变线程的相对优先级。一个线程的优先级是相对于其所属的进程的优先级而言的。

                     BOOL   SetThreadPriority(HANDLE hThread,intnPriority);

  其中参数hThread是指向待修改 优先级线程的句柄,nPriority可以是以下的值:

  THREAD_PRIORITY_LOWEST,
  THREAD_PRIORITY_BELOW_NORMAL,
  THREAD_PRIORITY_NORMAL,
  THREAD_PRIORITY_ABOVE_NORMAL,
  THREAD_PRIORITY_HIGHEST

  5、挂起及恢复线程

  先前我提到过可以创建挂起状态的线程(通过传递CREATE_SUSPENDED标志给函数CreateThread来实现)。当你这样做时,系统创建指定线程的核心对象,创建线程的栈,在CONTEXT结构中初始化线程CPU注册成员。然而,线程对象被分配了一个初始挂起计数值1,这表明了系统将不再分配CPU去执行线程。要开始执行一个线程,另一个线程必须调用ResumeThread并传递给它调用CreateThread时返回的线程句柄。

                                 DWORD ResumeThread(HANDLEhThread);

  一个线程可以被挂起多次。如果一个线程被挂起3次, 则该线程在它被分配CPU之前必须被恢复3次。除了在创建线程时使用CREATE_SUSPENDED标志,你还可以用SuspendThread函数挂起线程。

                                 DWORD SuspendThread(HANDLE hThread);  

CreateThread()函数的简单程序

windows多线程编程 win32多线程编程 多线程
  • Cry_Alone
  • Cry_Alone
  • 2016年04月21日 17:12
  • 218

c++利用winapi实现简单多线程

#include #include #include using namespace std; DWORD WINAPI FUN1Proc(LPVOID lpParameter); //线程函数入...
  • u011575841
  • u011575841
  • 2016年11月10日 15:33
  • 1577

WinSock 异步I/O模型[5]---完成端口+线程池技术

█ “完成端口”模型是迄今为止最复杂的一种 I/O 模型。但是,若一个应用程序同时需要管理很多的套接字, 那么采用这种模型,往往可以达到最佳的系统性能!但缺点是,该模型只适用于 Windows NT ...
  • u012372584
  • u012372584
  • 2017年02月21日 09:16
  • 303

消息处理线程

消息处理线程 //函数名称:IOThreadProc //函数功能:消息处理的线程 //处理对象:核心函数 //研究人员:长寿梦  DWORD WINAPI CP2PServ...
  • cuijinquan
  • cuijinquan
  • 2014年01月16日 16:01
  • 489

DWORD,BYTE,句柄类型

DWORD:就是double word,每个word为两个字节,所以double word就是四个字节,每个字节为8位,所以DWOD是32位 typedef unsigned long DWORD ...
  • Vivian_Chang
  • Vivian_Chang
  • 2014年03月02日 20:46
  • 1479

在window下的Mysql基本操作以接口的方式封装并提供出来,C++多线程操作

最近刚刚需要同时用到mysql和多线程,网上mysql和多线程的教程很多,但是能同时使用的资料没找到,不过通过网上的这些的资料,写了个demo来理解和理顺自己这几天的学习,分享一下。 Mysql...
  • catemo
  • catemo
  • 2016年11月07日 13:24
  • 485

多线程编程入门(一)

多线程简介1: 什么是多线程多线程,是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称...
  • zhang_alongzd
  • zhang_alongzd
  • 2016年09月24日 15:53
  • 517

Windows下多线程相关函数

Windows下多线程相关函数1)创建线程 CreateThreadWINBASEAPI _Ret_maybenull_ HANDLE WINAPI CreateThread( _In_opt...
  • yzhang6_10
  • yzhang6_10
  • 2016年04月14日 10:30
  • 513

Python:使用threading模块实现多线程编程

Python:使用threading模块实现多线程编程一[综述] Python这门解释性语言也有专门的线程模型,Python虚拟机使用GIL(Global Interpreter Lock,全局解释...
  • bravezhe
  • bravezhe
  • 2013年02月17日 15:39
  • 7183

Windows中定时器Timer使用中的注意事项

在任何语言任何操作系统下的开发中,定时器都是一个必不可少的功能,大部分的操作系统和语言都有内置的定时器接口可供调用。在windows API中有一组定时器相关函数,包括CreateTimerQueue...
  • vegeta34
  • vegeta34
  • 2017年02月08日 23:02
  • 738
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Windows下多线程编程技术及其实现
举报原因:
原因补充:

(最多只允许输入30个字)