屠菁-《操作系统》实验指导书(2016) 联系客服

发布时间 : 星期六 文章屠菁-《操作系统》实验指导书(2016)更新完毕开始阅读158879e53169a4517623a3a0

《操作系统》实验指导书

FALSE, // 不继承句柄 0, // 特殊的创建标志 NULL, // 新环境 NULL, // 当前目录 &si, // 启动信息结构 &pi ) ; // 返回的进程信息结构

// 释放对子进程的引用

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, // 缺省的安全性,子进程将具有访问权限 TRUE, // 手工重置事件 FALSE, // 初始时是非接受信号状态 g_szContinueEvent); // 事件名称 if (hEventContinue!=NULL)

{ std :: cout << \ // 创建子进程 if (:: CreateChild()) {

std :: cout << \

// 等待,直到子进程发出信号

std :: cout << \ :: WaitForSingleObject(hEventContinue, INFINITE);

:: Sleep(1500); // 删去这句试试 std :: cout << \endl;

}

// 清除句柄

:: CloseHandle(hEventContinue);

hEventContinue = INVALID_HANDLE_VALUE; } }

// 以下方法在子进程模式下被调用,其功能只是向父进程发出终止信号 void SignalParent() {

// 尝试打开句柄 std :: cout << \

27

《操作系统》实验指导书

HANDLE hEventContinue = :: OpenEvent( EVENT_MODIFY_STATE, // 所要求的最小访问权限 FALSE, // 不是可继承的句柄 g_szContinueEvent); // 事件名称 if (hEventContinue != NULL) {

:: SetEvent(hEventContinue); std :: cout << \ }

// 清除句柄

:: CloseHandle(hEventContinue) ;

hEventContinue = INVALID_HANDLE_VALUE; }

int main(int argc, char* argv[] ) {

// 检查父进程或是子进程是否启动

if (argc>1 && :: strcmp(argv[1] , \ { // 向父进程创建的事件发出信号 :: SignalParent() ;

} else { // 创建一个事件并等待子进程发出信号 :: WaitForChild() ; :: Sleep(1500) ;

std :: cout << \ }

return 0; }

步骤4:单击“Build”菜单中的“Compile 4-1.cpp”命令,并单击“是”按钮确认。系统对4-1.cpp进行编译。

步骤5:编译完成后,单击“Build”菜单中的“Build 4-1.exe”命令,建立4-1.exe可执行文件。

操作能否正常进行?如果不行,则可能的原因是什么?

____________________________________________________________________ ________________________________________________________________________ 步骤6:在工具栏单击“Execute Program” (执行程序) 按钮,执行4-1.exe程序。 运行结果 (分行书写。如果运行不成功,则可能的原因是什么?) :

1) __________________________________________________________________ 2) __________________________________________________________________ 3) __________________________________________________________________ 4) __________________________________________________________________ 5) __________________________________________________________________ 6) __________________________________________________________________ 这个结果与你期望的一致吗?(从进程并发的角度对结果进行分析) 阅读和分析程序4-1,请回答:

1) 程序中,创建一个事件使用了哪一个系统函数?创建时设置的初始信号状态是什么? a. __________________________________________________________________ b. __________________________________________________________________ 2) 创建一个进程 (子进程) 使用了哪一个系统函数?

____________________________________________________________________ 3) 从步骤6的输出结果,对照分析4-1程序,可以看出程序运行的流程吗?请简单描述:

28

《操作系统》实验指导书

____________________________________________________________________ ________________________________________________________________________ ________________________________________________________________________ ________________________________________________________________________ ________________________________________________________________________ ________________________________________________________________________

2. 互斥体对象

清单4-2的程序中显示的类CCountUpDown使用了一个互斥体来保证对两个线程间单一数值的访问。每个线程都企图获得控制权来改变该数值,然后将该数值写入输出流中。创建者实际上创建的是互斥体对象,计数方法执行等待并释放,为的是共同使用互斥体所需的资源 (因而也就是共享资源) 。

步骤7:在Visual C++ 窗口的工具栏中单击“打开”按钮,在“打开”对话框中找到并打开实验源程序4-2.cpp。

清单4-2 利用互斥体保护共享资源 // mutex项目

# include # include

// 利用互斥体来保护同时访问的共享资源 class CCountUpDown {

public:

// 创建者创建两个线程来访问共享值 CCountUpDown(int nAccesses) :

m_hThreadlnc(INVALID_HANDLE_VALUE) , m_hThreadDec(INVALID_HANDLE_VALUE) , m_hMutexValue(INVALID_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, // 缺省的安全性 0, // 缺省堆栈 DecThreadProc, // 类线程进程 reinterpret_cast (this) , // 线程参数 0, // 无特殊的标志 NULL) ; // 忽略返回的id

// 允许另一线程获得互斥体

:: ReleaseMutex(m_hMutexValue) ;

29

《操作系统》实验指导书

}

// 解除程序释放对对象的引用

virtual ~CCountUpDown()

{

:: CloseHandle(m_hThreadInc) ; :: CloseHandle(m_hThreadDec) ; :: CloseHandle(m_hMutexValue) ; }

// 简单的等待方法,在两个线程终止之前可暂停主调者 virtual void WaitForCompletion() {

// 确保所有对象都已准备好

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) {

// 等待访问数值

:: WaitForSingleObject(m_hMutexValue, INFINITE) ;

// 改变并显示该值 m_nValue += nStep;

std :: cout << “thread: ” << :: GetCurrentThreadId() << “value: ” << m_nvalue

<< “access: ” << m_nAccess << std :: endl;

// 发出访问信号并允许线程切换 --m_nAccess; :: sleep(l000) ; // 使显示速度放慢

// 释放对数值的访问

:: ReleaseMutex(m_hMutexValue) ; } }

static DWORD WINAPI IncThreadProc(LPVOID lpParam) {

// 将参数解释为 ?this? 指针 CCountUpDown* pThis =

reinterpret_cast < CCountUpDown* > (lpParam) ;

// 调用对象的增加方法并返回一个值

pThis -> DoCount(+1) ;

30