第1章 Visual C++开发环境介绍 1.1Visual C++概述 1.1.1Visual C++概述 Visual C++是微软公司推出的、使用极为广泛的、基于Windows平台的可视化集成开发环境,它和Visual Basic等其他软件一起构成了Visual Studio程序设计软件包。 2000年6月,微软公司宣布了Visual Studio .NET战略,现在Visual Studio .NET战略早已变为现实。Visual Studio .NET是用于创建和集成XML Web服务和应用程序的综合开发工具。Visual Studio .NET提供了一个高效环境,用户可在其中开发运行于新的Microsoft .NET平台上的广泛的应用程序。使用安全的和高性能的Microsoft .NET框架运行时环境,Visual Studio .NET提供用于设计、创建、测试和部署XML Web服务和应用程序的工具。 Visual Studio.NET提供了包括设计、编码、编译调试、数据库连接操作等基本功能和基于开放架构的服务器组件开发平台、企业开发工具和应用程序重新发布工具以及性能评测报告等高级功能。 Visual Studio.NET为Visual C++、Visual C# 和Visual Basic程序员提供了通用的开发环境,开发人员能在Visual C++、Visual C#之间自由转换; JScript程序员在创建ASP.NET和Web服务应用程序时也将得到Visual Studio.NET的支持; 而XML开发人员则非常喜欢它对XML文档、XML大纲和XSL转换的强大支持。 目前,Visual Studio的版本已从Visual Studio .NET、Visual Studio 2003、Visual Studio 2005升级到Visual Studio 2007。 Visual C++6.0是Visual C++开发工具的6.0版本,使用该版本的用户较多,并且相对上述版本,其使用较为简单,对计算机硬件配置要求比较低,很多场合仍以Visual C++6.0作为教学工具,因此本书的Windows系统实验部分也以Visual C++6.0为实验工具。 1.1.2Visual C++6.0的主要特性 Visual C++6.0的主要特性包括以下几点。 (1) 可定制的工具栏和菜单。用户可根据需要创建新的工具栏和菜单,使其适合自己的工作需要。 (2) 宏功能。可以根据用户的操作自动生成宏操作序列。 (3) 调试器。可以直接运行和调试程序,还可以使用宏语言来自动操作调试器。 (4) 项目工作区文件和项目文件。在Visual C++6.0中,项目工作区文件以 .dsw为后缀,项目文件以 .dsp为后缀。 (5) 一个项目工作区内可包含多个工程文件。要在当前项目工作区中增加一个工程,可以打开该项目工作区,然后选择【Project】→【Insert Project into Workspace】命令。通过选择【Project】→【Set Active Project】命令,可以设置当前活动工程。该特性使得用户可以在不同工程之间复制代码和资源。 第 1 章 Visual C++开发环境介绍 计算机操作系统实验指导 1.1.3Visual C++6.0的窗口 Visual C++6.0是一种集成开发环境(Integrated Development Environment,IDE),它拥有友好的可视化界面。除了具有和Windows窗口一样的标题栏、菜单栏、工具栏和状态栏外,还有一些窗口,其中包括项目工作区窗口、代码编辑区窗口、输出窗口,如图11所示。 图11Visual C++窗口 1. 项目工作区窗口 项目工作区是Visual C++6.0最重要的组成部分,程序员的大部分工作都在集成开发环境中完成,在一个项目工作区中,可以处理一个工程和它所包含的文件、一个工程的子工程、多个相互独立的工程和多个相互依赖的工程。项目工作区窗口在屏幕的左侧,如图11所示。项目工作区窗口的底部有一组标签,用于从不同的角度(视图)查看项目中包含的工程文件信息,单击某个标签可以切换到对应的视图。 每个项目视图都有一个相应的文件夹,包含了关于该项目的各种元素。展开该文件夹可以显示该视图方式下项目工作区的详细信息。项目工作区包含三种视图。 (1) File View(文件视图): 显示所创建的工程中包含的文件。 (2) Class View (类视图): 显示项目中定义的类,展开可查看类的数据成员和成员函数以及全局变量、函数和类型定义。 (3) Resource View(资源视图): 显示项目中所包含的资源文件。 2. 代码编辑区窗口 代码编辑区窗口位于整个屏幕的中部,如图11所示,它是程序员进行代码开发的场所,供程序员编写、修改和调试代码时使用。 3. 输出窗口 输出窗口位于整个屏幕的下方,如图11所示,主要用于显示代码调试和运行中的相关信息。主要包括以下信息。 (1) 编译(Compile)信息: 列出代码和资源编译过程和编译过程中产生的警告(Warning)和错误(Error)。 (2) 链接(Link)信息: 列出工程对目标模块(OBJ)链接过程中产生的警告(Warning)和错误(Error)。 (3) 调试(Debug)信息: 在调试状态下,输出有关的调试信息。 1.2Visual C++6.0控制台程序 1.2.1Visual C++6.0控制台程序的建立 Visual C++6.0分为学习版、专业版和企业版。Visual C++提供了一种控制台操作方式,初学者使用它应该从这里开始。Win32控制台程序(Win32 Console Application)是一类Windows程序,它不使用复杂的图形用户界面,程序与用户交互时通过一个标准的正文窗口,通过几个标准的输入输出流(I/O Streams)进行。下面对使用Visual C++编写简单的控制台程序作一个最初步的介绍。 (1) 安装Visual C++6.0。运行Visual Studio软件中的setup.exe程序,选择安装Visual C++6.0,然后按照安装程序的指导完成安装过程。 (2) 启动Visual C++6.0。安装完成后,选择【开始】→【程序】→【开发工具】→【Microsoft Visual Studio 6.0】→【Microsoft Visual C++6.0】命令即可运行(也可在Window桌面上建立一个快捷方式,以后可双击运行),如图12所示。 图12Microsoft Visual C++6.0的启动 (3) 选择控制台工程。进入Visual C++6.0 环境后,选择【File】→New命令,然后在Projects选项卡中选择Win32 Console Application建立一个控制台工程文件,在 【Project name】文本框中输入工程文件名,在Location中选择工程文件所在的路径,选择完毕单击OK按钮,如图13所示。 图13控制台工程文件的建立 (4) 建立工程文件。屏幕上弹出如图14所示的对话框后,可以选择任意一项,这里选择An empty project项,然后单击Finish按钮。 图14建立一个空的工程 (5) 编辑C++程序。 选择Project→Add To Project→New命令,为工程添加新的C++源文件,如图15所示; 然后在代码编辑区输入源程序,存盘。 图15在空工程中添加新的C++源文件 (6) 编译源程序。选择Build→Build命令(F7为快捷键),系统将会在输出窗口给出所有的错误信息和警告信息,如图16所示。当所有错误修正之后,系统将会生成扩展名为exe的可执行文件。对于输出窗口给出的错误信息,双击可以使输入焦点跳转到引起错误的源代码处以进行修改。 图16编辑、编译源程序 (7) 执行程序。选择Build→Execute命令(Ctrl+F5为快捷键),执行程序,将会打开一个DOS窗口,按照程序输入要求正确输入数据后,程序即可正确执行,如图17所示。 图17在DOS窗口执行程序 (8) 调试程序。在编写较长的程序时,能够一次成功而不含有任何错误决非易事,这需要进行长期、大量的练习。编写的程序若已没有编译错误,可以成功运行。对于程序中的错误,Visual C++6.0提供了易用且有效的调试手段。 在工具栏中选择Build→Start Debug→Go命令,程序进入调试状态,可以进行单步执行调试程序。其中,单步跟踪进入子函数(Step Into,F11为快捷键),每按一次F11键,程序执行一条无法再进行分解的程序行; 单步跟踪跳过子函数(Step Over,F10为快捷键),每按一次F10键,程序执行一行; Watch窗口可以显示变量名及其当前值,在单步执行的过程中,可以在Watch窗口(屏幕的下方,如图18所示)中加入所需观察的变量, 以辅助监视,随时了解变量当前的情况; 同时,为方便较大规模程序的跟踪,可以设置断点(F9为快捷键),断点处所在程序行的左侧会出现一个红色圆点。当选择Go命令时,程序执行到断点处将暂停执行,以方便用户进行变量观察。取消断点只需在代码断点处再次按F9键即可。 图18调试程序 1.2.2Visual C++6.0工程的文件组成 建立一个Visual C++6.0控制台程序后,系统会自动创建一个目录,该目录下会生成很多文件和目录。这些文件可分为工作区文件和项目文件、应用程序源文件和头文件、资源文件和预编译头文件,以及Debug或Release目录。 1. 工作区文件和项目文件 工作区文件和项目文件主要用于保存和更新工作区和项目信息,主要包括下面的文件。 (1) Sample.dsw: 工作区文件,它包含当前工作区中的项目信息。 (2) Sample.dsp: 项目文件,它包含当前项目的位置、所包含的文件等信息。 (3) Sample.clw: 该文件包含MFC(Microsoft Foundation Class)向导中用来编辑的现有类或增加新类的信息。 2. 应用程序源文件和头文件 应用程序源文件和头文件是工程的主体。 (1) Sample.h: 应用程序的主头文件,它包含所有全局符号和用于包含其他头文件的#include 伪指令。 (2) Sample.cpp: 应用程序的主源文件。 3. 资源文件和预编译头文件 基于MFC的Windows应用程序一般都少不了应用程序资源的支持,工程中会创建一些与资源有关的文件,同时,与MFC应用程序相关的预编译头文件也会被创建。 (1) Sample.rc: 项目的头文件。 (2) Resource.h: 项目的资源文件。 (3) stdafx.cpp和stdafx.h: 这两个文件用于建立一个预编译的头文件Sample.pch和一个预定义的类型文件stdafx.obj。由于MFC体系结构非常大,包含许多头文件,如果每次都编译,比较费时,因此把常用的MFC头文件都放在stdafx.h中,然后让stdafx.cpp包含这个stdafx.h文件。这样,由于编译器可以识别哪些文件已经编译过,所以stdafx.cpp就只编译一次,并生成所谓的预编译头文件。如果以后在编译时不想让有些MFC头文件每次都编译,也可以将它加入到stdafx.h中。采用预编译头文件可以加快编译过程。 4. Debug目录或Release目录 在Visual C++6.0中,一个工程可产生两种不同版本的可执行程序: Debug版本和Release版本。两个目录下都存放编译、链接时产生的中间文件及生成的可执行程序。不同的是,Debug版本包含用于调试的信息和代码,而Release版本不包含,因此Release版本产生的可执行程序文件比Debug版本要小。 1.3MSDN简介 1.3.1MSDN概述 MSDN是Microsoft Developer Network的简称。它为使用微软程序设计语言及其开发工具的开发者提供了大量的技术资料。MSDN是专门为Windows环境开发人员提供的技术光盘宝库,也为对微软技术内幕感兴趣的人员提供了研究Windows的窗口。 MSDN是微软公司为使用微软产品及技术的开发人员所设计的一项资源订阅服务,微软公司通过定期寄送MSDN光盘的形式,将开发过程中所需要的各种资料、工具及产品送到开发人员手中,以满足开发人员在软件研发过程中的各种需求。 为了配合不同类型的开发工作,MSDN提供不同等级的产品。企业或个人可根据需要订购不同等级的产品,取得微软的开发平台、系统开发包(System Development Kit,SDK)、BackOffice或开发工具,并定期获得关于微软公司的最新信息。 1. MSDN包含的内容 MSDN含有微软全部的技术文件,主要内容有: (1) 程序设计语言(如Visual Basic、Visual C++等)的技术文件。 (2) 范例代码(Sample Code)。 (3) 技术规范(Specifications)。 (4) 知识库与勘误表(Knowledge Base and Bug Lists)。 (5) 书籍及期刊。 (6) 产品手册。 2. MSDN的使用对象 使用MSDN的人员包括: (1) 驱动程序开发者。 (2) 使用微软产品、开发工具及相关技术的人员。 (3) 需要不断在微软产品的基础上更新其相关产品的开发机构。 (4) 需要使用微软操作系统和其他产品来开发及测试自己的应用程序的各类人员。 3. MSDN内容简介 MSDN分三个等级: 基本版、专业版和通用版。其中基本版适用于初步投入Windows平台的软件技术人员; 专业版适用于专门从事Windows平台应用软件、游戏软件、驱动程序开发的人员使用; 通用版适用于专门进行商用系统、企业解决方案、Internet解决方案的开发人员使用。三个版本的内容不尽相同,基本版的内容大致如下: (1) 软件开发工具产品文件。 (2) 系统开发包(SDK)相关文件,涵盖BaceOffice系列及Office系列。 (3) 驱动程序开发包(Driver Development Kit,DDK)相关文件。 (4) 开发相关技术文件。 (5) 范例程序代码。 (6) 重要的技术规范、书籍及期刊。 (7) 开发人员知识库,疑难问题解答。 1.3.2MSDN使用 得到MSDN光盘之后,使用时首先要进行安装,安装之前,要确保用于安装的计算机中已经安装有Microsoft Internet Exporer,否则无法执行安装程序。安装过程非常简单,只要执行安装程序setup.exe即可。 Visual C++6.0提供了详细的帮助信息,用户通过选择集成开发环境中的Help→Contents命令就可以进入帮助系统。或者在源文件编辑器中把光标定位在一个需要查询的单词处,然后按F1键也可以进入Visual C++6.0的帮助系统,如图19所示。用户通过Visual C++6.0的帮助系统可以获得几乎所有的Visual C++6.0的技术信息,这也是Visual C++作为一个非常友好的开发环境所具有的一个特色。 图19MSDN Help 第2章 Windows的进程管理 2.1实验一: 线程的创建与撤销 2.1.1实验目的 (1) 熟悉Windows系统提供的线程创建与撤销系统调用。 (2) 掌握Windows系统环境下线程的创建与撤销方法。 2.1.2实验准备知识: 相关API函数介绍 1. 线程创建 CreateThread()完成线程的创建。它在调用进程的地址空间上创建一个线程,执行指定的函数,并返回新建立线程的句柄。 原型: HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes,// 安全属性指针 DWORD dwStackSize, // 线程堆栈大小 LPTHREAD_START_ROUTINE lpStartAddress, // 线程所要执行的函数 LPVOID lpParameter, // 线程对应函数要传递的参数 DWORD dwCreationFlags, // 线程创建后所处的状态 LPDWORD lpThreadId // 线程标识符指针 ); 参数说明: (1) lpThreadAttributes: 为线程指定安全属性。为NULL时,线程得到一个默认的安全描述符。 (2) dwStackSize: 线程堆栈的大小。其值为0时,其大小与调用该线程的线程堆栈大小相同。 (3) lpStartAddress: 指定线程要执行的函数。 (4) lpParameter: 函数中要传递的参数。 (5) dwCreationFlags: 指定线程创建后所处的状态。若为CREATE_SUSPENDED,表示创建后处于挂起状态,用ResumeThread()激活后线程才可执行。若该值设为0,表示线程创建后立即执行。 (6) lpThreadId: 用一个32位的变量接收系统返回的线程标识符。若该值设为NULL,系统不返回线程标识符。 返回值: 如果线程创建成功,将返回该线程的句柄; 如果失败,系统返回NULL,可以调用函数GetLastError查询失败的原因。 用法举例: staticHANDLE hHandle1=NULL; // 用于存储线程返回句柄的变量 DWORD dwThreadID1; // 用于存储线程标识符的变量 // 创建一个名为ThreadName1的线程 hHandle1=CreateThread((LPSECURITY_ATTRIBUTES) NULL, 0, (LPTHREAD_START_ROUTINE) ThreadName1, (LPVOID) NULL, 0, &dwThreadID1); 2. 撤销线程 ExitThread()用于撤销当前线程。 原型: VOID ExitThread( DWORD dwExitCode// 线程返回码 ); 参数说明: dwExitCode: 指定线程返回码,可以调用GetExitCodeThread()查询返回码的含义。 返回值: 该函数没有返回值。 第 2 章 Windows的进程管理 计算机操作系统实验指导 用法举例: ExitThread(0); // 参数0表示要撤销进程中的所有线程 3. 终止线程 TerminateThread()用于终止当前线程。该函数与ExitThread()的区别在于,ExitThread()在撤销线程时将该线程所拥有的资源全部归还给系统,而TerminateThread()不归还资源。 原型: BOOL TerminateThread( HANDLE hThread, // 线程句柄 DWORD dwExitCode// 线程返回码 ); 参数说明: (1) hThread: 要终止线程的线程句柄。 (2) dwExitCode: 指定线程返回码,可以调用GetExitCodeThread()查询返回码的含义。 返回值: 函数调用成功,将返回一个非0值; 若失败,返回0,可以调用函数GetLastError()查询失败的原因。 4. 挂起线程 Sleep()用于挂起当前正在执行的线程。 原型: VOID Sleep( DWORD dwMilliseconds// 挂起时间 ); 参数说明: dwMilliseconds: 指定挂起时间,单位为ms(毫秒)。 返回值: 该函数无返回值。 5. 关闭句柄 函数CloseHandle()用于关闭已打开对象的句柄,其作用与释放动态申请的内存空间类似,这样可以释放系统资源,使进程安全运行。 原型: BOOL CloseHandle( HANDLE hObject// 要关闭对象的句柄 ); 参数说明: hObject: 已打开对象的句柄。 返回值: 如果函数调用成功,则返回值为非0值; 如果函数调用失败,则返回值为0。若要得到更多的错误信息,调用函数GetLastError()查询。 2.1.3实验内容 使用系统调用 CreateThread()创建一个子线程,并在子线程序中显示: Thread is Runing!。为了能让用户清楚地看到线程的运行情况,使用Sleep()使线程挂起5s,之后使用ExitThread(0)撤销线程。 2.1.4实验要求 能正确使用CreateThread()、ExitThread()及Sleep()等系统调用,进一步理解进程与线程理论。 2.1.5实验指导 本实验在Windows XP、Microsoft Visual C++6.0环境下实现,利用Windows SDK(System Development Kit)提供的API(Application Program Interface,应用程序接口)完成程序的功能。实验在Windows XP环境下安装Microsoft Visual C++6.0后进行,由于Microsoft Visual C++6.0是一个集成开发环境,其中包含了Windows SDK所有工具和定义,所以安装了Microsoft Visual C++6.0后不用特意安装SDK。实验中所有的API是操作系统提供的用来进行应用程序开发的系统功能接口。 (1) 首先启动安装好的Microsoft Visual C++6.0。 (2) 在Microsoft Visual C++6.0环境下选择File→New命令,然后在Project选项卡中选择Win32 Console Application建立一个控制台工程文件。 (3) 由于CreateThread()等函数是Microsoft Windows操作系统的系统调用,因此在图21中选择An application that supports MFC,之后单击Finish按钮。 图21建立一个MFC支持的应用程序 (4) 之后将打开Microsoft Visual C++6.0编辑环境(见图22),按本实验的要求编辑C程序,之后编译、链接并运行该程序即可。 图22Microsoft Visual C++6.0编辑环境 2.1.6实验总结 在Windows系统中进程是资源的拥有者,线程是系统调度的单位。进程创建后,其主线程也随即被创建。在该实验中,又创建了一个名为ThreadName1的子线程,该子线程与主线程并发地被系统调度。为了能看到子线程的运行情况,在主线程创建了子线程后,将主线程挂起5s以确保子线程能够运行完毕,之后调用ExitThread(0)将所有线程(包括主、子线程序)撤销。线程运行如图23所示。 图23线程运行 2.1.7源程序 // ThreadCreate.cpp: Defines the entry point for the console application. #include "stdafx.h" #include "ThreadCreate.h" #ifdef_DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[]=__FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // The one and only application object CWinApp theApp; using namespace std; void ThreadName1(); staticHANDLE hHandle1=NULL; //用于存储线程返回句柄的变量 DWORD dwThreadID1; //用于存储线程标识符的变量 int_tmain(int argc, TCHAR* argv[], TCHAR* envp[]) { int nRetCode=0; hHandle1=CreateThread((LPSECURITY_ATTRIBUTES) NULL, 0, (LPTHREAD_START_ROUTINE) ThreadName1, //创建一个名ThreadName1的线程 (LPVOID) NULL, 0, &dwThreadID1); Sleep(5000); //将主线程挂起5s CloseHandle(hHandle1); //关闭句柄 ExitThread(0); //撤销线程 return nRetCode; } void ThreadName1()//线程对应的函数 { printf("Thread is Runing!\n"); } 2.1.8实验展望 可以进一步完善程序功能,请思考以下问题。 (1) 如何向线程对应的函数传递参数?一个参数如何传递,多个参数又如何传递? (2) 深入理解线程与进程的概念,在Windows环境下何时使用进程,何时使用线程? 2.2实验二: 线程的同步 2.2.1实验目的 (1) 进一步掌握Windows系统环境下线程的创建与撤销。 (2) 熟悉Windows系统提供的线程同步API。 (3) 使用Windows系统提供的线程同步API解决实际问题。 2.2.2实验准备知识: 相关API函数介绍 2.2.2.1等待对象 等待对象(wait functions)函数包括等待一个对象(WaitForSingleObject())和等待多个对象(WaitForMultipleObject())两个API函数。 1. 等待一个对象 WaitForSingleObject()用于等待一个对象。它等待的对象可以为以下对象之一。  Change notification: 变化通知。  Console input: 控制台输入。  Event: 事件。  Job: 作业。  Mutex: 互斥信号量。  Process: 进程。  Semaphore: 计数信号量。  Thread: 线程。  Waitable timer: 定时器。 原型: DWORD WaitForSingleObject( HANDLE hHandle, // 对象句柄 DWORD dwMilliseconds// 等待时间 ); 参数说明: (1) hHandle: 等待对象的对象句柄。该对象句柄必须为SYNCHRONIZE访问。 (2) dwMilliseconds: 等待时间,单位为ms。若该值为0,函数在测试对象的状态后立即返回,若为INFINITE,函数一直等待下去,直到接收到一个信号将其唤醒,如表21所示。 返回值: 如果成功返回,其返回值说明是何种事件导致函数返回。 表21函数描述 访问描述 WAIT_ABANDONED 等待的对象是一个互斥(Mutex) 对象,该互斥对象没有被拥有它的线程释放,它被设置为不能被唤醒 WAIT_OBJECT_0指定对象被唤醒 WAIT_TIMEOUT超时 用法举例: staticHANDLE hHandle1=NULL; DWORDdRes; dRes=WaitForSingleObject(hHandlel,10); //等待对象的句柄为hHandle1,等待时间为10ms 2. 等待多个对象 WaitForMultipleObject()在指定时间内等待多个对象,它等待的对象与WaitForSingleObject()相同。 原型: DWORD WaitForMultipleObjects( DWORD nCount,// 句柄数组中的句柄数 CONST HANDLE *lpHandles, // 指向对象句柄数组的指针 BOOL fWaitAll, // 等待类型 DWORD dwMilliseconds// 等待时间 ); 参数说明: (1) nCount: 由指针*lpHandles指定的句柄数组中的句柄数,最大数是MAXIMUM_WAIT_OBJECTS。 (2) *lpHandles: 指向对象句柄数组的指针。 (3) fWaitAll: 等待类型。若为TRUE,当由lpHandles数组指定的所有对象被唤醒时函数返回; 若为 FALSE,当由lpHandles数组指定的某一个对象被唤醒时函数返回,且由返回值说明是由于哪个对象引起的函数返回。 (4) dwMilliseconds: 等待时间,单位为ms。若该值为0,函数测试对象的状态后立即返回; 若为INFINITE,函数一直等待下去,直到接收到一个信号将其唤醒。 返回值: 如果成功返回,其返回值说明是何种事件导致函数返回。 各参数的描述如表22所示。 表22各参数描述 访问描述 WAIT_OBJECT_0 to (WAIT_OBJECT_0+nCount-1)若bWaitAll为TRUE,返回值说明所有被等待的对象均被唤醒; 若bWaitAll为FALSE,返回值减去WAIT_OBJECT_0说明lpHandles数组下标指定的对象满足等待条件。如果调用时多个对象同时被唤醒,则取多个对象中最小的那个数组下标 WAIT_ABANDONED_0 to (WAIT_ABANDONED_0+nCount-1)若bWaitAll为TRUE,返回值说明所有被等待的对象均被唤醒,并且至少有一个对象是没有约束的互斥对象; 若bWaitAll为FALSE,返回值减去WAIT_ABANDONED_0说明lpHandles数组下标指定的没有约束的互斥对象满足等待条件 WAIT_TIMEOUT超时且参数bWaitAll指定的条件不能满足 2.2.2.2信号量对象(Semaphore) 信号量对象(Semaphore)包括创建信号量(CreateSemaphore())、打开信号量(OpenSemaphore())及增加信号量的值(ReleaseSemaphore())API函数。 1. 创建信号量 CreateSemaphore()用于创建一个信号量。 原型: HANDLE CreateSemaphore( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,// 安全属性 LONG lInitialCount, // 信号量对象的初始值 LONG lMaximumCount,// 信号量的最大值 LPCTSTR lpName // 信号量名 ); 参数说明: (1) lpSemaphoreAttributes: 指定安全属性,为NULL时,信号量得到一个默认的安全描述符。 (2) lInitialCount: 指定信号量对象的初始值。该值必须大于等于0,小于等于lMaximumCount。当其值大于0时,信号量被唤醒。当该函数释放了一个等待该信号量的线程时,lInitialCount值减1,当调用函数ReleaseSemaphore()时,按其指定的数量加一个值。 (3) lMaximumCount: 指出该信号量的最大值,该值必须大于0。 (4) lpName: 给出信号量的名字。 返回值: 信号量创建成功,将返回该信号量的句柄。如果给出的信号量名是系统已经存在的信号量,将返回这个已存在信号量的句柄。如果失败,系统返回NULL,可以调用函数GetLastError()查询失败的原因。 用法举例: staticHANDLE hHandle1=NULL; //定义一个句柄 //创建一个信号量,其初值为0,最大值为5,信号量的名字为"SemphoreName1" hHandle1=CreateSemaphore(NULL,0,5,"SemphoreName1"); 2. 打开信号量 OpenSemaphore()用于打开一个信号量。 原型: HANDLE OpenSemaphore( DWORD dwDesiredAccess, // 访问标志 BOOL bInheritHandle, // 继承标志 LPCTSTR lpName // 信号量名 ); 参数说明: (1) dwDesiredAccess: 指出打开后要对信号量进行何种访问,如表23所示。 表23访问状态 访问描述 SEMAPHORE_ALL_ACCESS可以进行任何对信号量的访问 SEMAPHORE_MODIFY_STATE 可使用ReleaseSemaphore()修改信号量的值,使信号量成为可用状态 SYNCHRONIZE使用等待函数(wait functions),等待信号量成为可用状态 (2) bInheritHandle: 指出返回的信号量句柄是否可以继承。 (3) lpName: 给出信号量的名字。 返回值: 信号量打开成功,将返回该信号量的句柄; 如果失败,系统返回NULL,可以调用函数GetLastError()查询失败的原因。 用法举例: staticHANDLE hHandle1=NULL;