《《WindowsXP线程同步》实验指导书(模板).pdf》由会员分享,可在线阅读,更多相关《《WindowsXP线程同步》实验指导书(模板).pdf(10页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、实验 3 Windows XP 线程同步(实践估计时间:100 分钟)3.1 背景知识 Windows xp 提供的常用对象可分成三类:核心应用服务、线程同步和线程间通信,其中,开发人员可以使用线程同步对象来协调线程和进程的工作,以使其共享信息并执行任务。此类对象包括互锁数据、临界区、事件、互斥信号量等。多线程编程中关键的一步是保护所有的共享资源,工具主要有互锁函数、临界区和互斥信号量等;另一个实质性部分是协调线程使其完成应用程序的任务,为此,可利用内核中的事件对象和信号。在进程内或进程间实现线程同步的最方便的方法是使用事件对象,这一组内核对象允许一个线程对其受信状态进行直接控制(见 表 3-
2、1)。表 3-1 用于管理事件对象 API API 名称 描述 CreateEve nt()在内核中创建一个新的事件对象。此函数允许有安全性设置、手工还是自动重置的标志以及初始 时已接收还是未接收信号状态的标志。OpenEvent()创建对已经存在的事件对象的引用。此 API 函数 需要名称、继承标志和所需的访问级别。SetEvent()将手工重置事件转化为已接收信号状态。ResetEven t()将手工重置事件转化为非接收信号状态。PulseEvnt()将自动重置事件对象转化为已接收信号状态。当系统释放所有的等待它的线程时此种转化立即发 生。与事件对象类似,互斥信号量容易创建、打开、使用并清
3、除。利用 CreateMutex()API 函数可创建互斥信号量,创建时还可以指定一个初始的拥有权标志,通过使用这个标志,只有当线程完成了资源的所有的初始化工作时,才允许创建线程释放互斥信号量。为 了 获 得 互 斥 信 号 量,首 先,想 要 访 问 调 用 的 线 程 可使 用 OpenMutex()API 函数来获得指向对象的句柄;然后,线程将这个句柄提供给一个等待函数。当内核将互斥信号量对象发送给等待线程时,就表明该线程获得了互斥信号量的拥有权。当线程获得拥有权时,线程控制了对共享资源的访问必须设法尽快地放弃互斥信号量。放弃共享资源时需要在该对象上调用 ReleaseMutex()AP
4、I。然后系统负责将互斥信号量拥有权传递给下一个等待着的线程(由到达时间决定顺序)。3.2 实践目的 在本实践中,通过对事件和互斥信号量对象的了解,加深对 Windows xp 线程同步的理解。1)回顾系统进程、线程的有关概念,加深对 Windows xp 的理解。2)了解事件和互斥信号量对象。3)通过分析实践程序,了解管理事件对象的 API。4)了解在进程中如何使用事件对象。5)了解在进程中如何使用互斥信号量对象。6)了解父进程创建子进程的程序设计方法。3.3 工具/准备工作 在开始本实践之前,请回顾教科书的相关内容。您需要做以下准备:1)一台运行 Windows xp Professiona
5、l 操作系统的计算机。2)计算机中需安装 Visual C+6.0 专业版或企业版。3.4 实践内容与步骤 1.事件对象 在进程间使用事件。父进程启动时,利用 CreateEvent()API 创建一个命名的、可共享的子进程,然后等待子进程向事件发出信号并终止父进程。在创建时,子进程通过 OpenEvent()API 打开事件对象,调用 SetEvent()API 使其转化为已接收信号状态。两个进程在发出信号之后几乎立即终止。步骤 1:登录进入 Windows xp Professional。步骤 2:在“开始”菜单中单击“程序”、“Microsoft Visual Studio 6.0”“M
6、icrosoft Visual C+6.0”,进 入 Visual C+窗口。步骤 3:在工具栏单击“新建”按钮,编写代码保存为 3-1.cpp。程序功能:创建和打开事件对象在进程间传送信号。参考类和函数:windows.h、iostream、CreateChild()、szFilename、GetModuleFileName、szCmdLine、CloseHandle、WaitForChild()。参考代码:/event 项目#include#include /以下是句柄事件。实际中很可能使用共享的包含文件来进行通讯 static LPCTSTR g_szContinueEvent=w2kd
7、g.EventDemo.event.Continue;/本方法只是创建了一个进程的副本,以子进程模式(由命令行指定)工作 BOOL CreateChild()/提取当前可执行文件的文件名 TCHAR szFilenameMAX_PATH;:GetModuleFileName(NULL,szFilename,MAX_PATH);/格式化用于子进程的命令行,指明它是一个 EXE 文件和子进程 TCHAR szCmdLineMAX_PATH;:sprintf(szCmdLine,%schild,szFilename);/子进程的启动信息结构 STARTUPINFO si;:ZeroMemory(re
8、interpret_cast(&si),sizeof(si);si.cb=sizeof(si);/必须是本结构的大小 /返回的子进程的进程信息结构 PROCESS_INFORMATION pi;/使用同一可执行文件和告诉它是一个子进程的命令行创建进程 BOOL bCreateOK=:CreateProcess(szFilename,/生成的可执行文件名 szCmdLine,/指示其行为与子进程一样的标志 NULL,/子进程句柄的安全性 NULL,/子线程句柄的安全性 FALSE,/不继承句柄 0,/特殊的创建标志 NULL,/新环境 NULL,/当前目录&si,/启动信息结构&pi);/返回的
9、进程信息结构/释放对子进程的引用 if(bCreateOK):CloseHandle(pi.hProcess);:CloseHandle(pi.hThread);return(bCreateOK);/下面的方法创建一个事件和一个子进程,然后等待子进程在返回前向事件发出信号 void WaitForChild()/create a new event object for the child process/to use when releasing this process HANDLE hEventContinue=:CreateEvent(NULL,/缺省的安全性,子进程将具有访问权限 T
10、RUE,/手工重置事件 FALSE,/初始时是非接受信号状态 g_szContinueEvent);/事件名称 if(hEventContinue!=NULL)std:cout event created std:endl;/创建子进程 if(:CreateChild()std:cout chlid created std:endl;/等待,直到子进程发出信号 std:cout Parent waiting on child.std:endl;:WaitForSingleObject(hEventContinue,INFINITE);:Sleep(1500);/删除这句试试 std:cout
11、parent received the envent signaling from child std:endl;/清除句柄:CloseHandle(hEventContinue);hEventContinue=INVALID_HANDLE_VALUE;/以下方法在子进程模式下被调用,其功能只是向父进程发出终止信号 void SignalParent()/尝试打开句柄 std:cout child process begining.std:endl;HANDLE hEventContinue=:OpenEvent(EVENT_MODIFY_STATE,/所要求的最小访问权限 FALSE,/不是
12、可继承的句柄 g_szContinueEvent);/事件名称 if(hEventContinue!=NULL):SetEvent(hEventContinue);std:cout event signaled 1&:strcmp(argv1,child)=0)/向父进程创建的事件发出信号:SignalParent();else /创建一个事件并等待子进程发出信号:WaitForChild();:Sleep(1500);std:cout Parent released.std:endl;return 0;步骤 4:单击“Build”菜单中的“Compile 3-1.cpp”命令,单击“是”按钮
13、确认,系统对 3-1.cpp 进行编译。步骤 5:编译完成后,单击“Build”菜单中的“Build3-1.exe”命令,建立 3-1.exe 可执行文件。操作能否正常进行,如果不行,原因是什么?步骤 6:在工具栏单击“Execute program”按钮,执行 3-1.exe 程序。运行结果(分行书写,如果不成功,原因是什么?):1)2)3)4)5)6)这个结果与你期望的一致吗?(从进程并发的角度对结果进行分析)。请回答:1)程序中,创建一个事件使用了哪一个系统函数?创建时设置的初始信号状态是什么?a)b)2)创建一个进程(子进程)使用了哪一个系统函数?2.互斥信号量对象 使用互斥信号量来保
14、证对两个线程间单一数值的访问。每个线程都企图获得控制权来改变该数值,然后将该数值写入输出流中。创建者实际上创建的是互斥信号量对象,计数方法执行等待并释放,为的是共同使用互斥信号量所需的资源(因而也就是共享资源)。步骤 1:在工具栏单击“新建”按钮,编写代码保存为 3-2.cpp。程序功能:利用互斥信号量保护共享资源 参考类与函数:windows.h、iostream、class CCountUpDown、WaitForCompletion()、DoCount()、ReleaseMutex()、步骤 2:单击“Build”菜单中的“Compile 3-2.cpp”命令,再单击“是”按钮确认,系统
15、对 3-2.cpp 进行编译。步骤 3:编译完成后,单击“Build”菜单中的“Build 3-2.exe”命令,建立 3-2.exe 可执行文件。操作能否正常进行,如果不行,原因是什么?参考代码:/mutex 项目#include#include /利用互斥体来保护同时访问的共享资源 class CCountUpDown public:/创建者创建两个线程来访问共享值 CCountUpDown(int nAccesses):m_hThreadInc(INVALID_HANDLE_VALUE),m_hThreadDec(INVALID_HANDLE_VALUE),m_hMutexValue(I
16、NVALID_HANDLE_VALUE),m_nValue(0),m_nAccess(nAccesses)/创建互斥体用于访问数值 m_hMutexValue=:CreateMutex(NULL,/缺省的安全性 TRUE,/初始时拥有,在所有的初始化结束时将释 放 NULL);/匿名的 m_hThreadInc=:CreateThread(NULL,/缺省的安全性 0,/缺省堆栈 IncThreadProc,/类线程进程 reinterpret_cast(this),/线程参数 0,/无特殊的标志 NULL);/忽略返回的 id m_hThreadDec=:CreateThread(NULL,
17、/缺省的安全性 0,/缺省堆栈 DecThreadProc,/类线程进程 reinterpret_cast(this),/线程参数 0,/无特殊的标志 NULL);/忽略返回的 id /允许另一线程获得互斥体:ReleaseMutex(m_hMutexValue);/解除程序释放对对象的引用 virtual CCountUpDown():CloseHandle(m_hThreadInc);:CloseHandle(m_hThreadDec);:CloseHandle(m_hMutexValue);/简单的等待方法,在两个线程终止之前可暂停主调者 virtual void WaitForComp
18、letion()/确保所有对象都已准备好 if(m_hThreadInc!=INVALID_HANDLE_VALUE&m_hThreadDec!=INVALID_HANDLE_VALUE)/等待两者完成 (顺序并不重要):WaitForSingleObject(m_hThreadInc,INFINITE);:WaitForSingleObject(m_hThreadDec,INFINITE);protected:/改变共享资源的简单的方法 virtual void DoCount(int nStep)/循环,直到所有的访问都结束为止 while(m_nAccess 0)/等待访问数值:Wait
19、ForSingleObject(m_hMutexValue,INFINITE);/改变并显示该值 m_nValue+=nStep;endl;std:cout thread:GetCurrentThreadId()value:m_nValueaccess:m_nAccess std:/发出访问信号并允许线程切换-m_nAccess;:Sleep(1000);/释放对数值的访问:ReleaseMutex(m_hMutexValue);static DWORD WINAPI IncThreadProc(LPVOID lpParam)/将参数解释为 this 指针 CCountUpDown*pThis
20、=reinterpret_cast(lpParam);/调用对象的增加方法并返回一个值 pThis-DoCount(+1);return(0);static DWORD WINAPI DecThreadProc(LPVOID lpParam)/将参数解释为 this指针 CCountUpDown*pThis=reinterpret_cast(lpParam);/调用对象的减少方法并返回一个值 pThis-DoCount(-1);return(0);protected:HANDLE m_hThreadInc;HANDLE m_hThreadDec;HANDLE m_hMutexValue;int m_nValue;int m_nAccess;void main()CCountUpDown ud(50);ud.WaitForCompletion();步骤 4:在工具栏单击“Execute program”按钮,执行 3-2.exe 程序。请描述运行结果(如果运行不成功,则可能的原因是什么?):