本文首先讨论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进程时,它的第一个线程称为主线程,它 由系统自动生成,然后可由这个主线程生成额外的线程,这些线程,又可生成更多的线程。