当前位置:文档之家› 操作系统实验报告

操作系统实验报告

操作系统实验报告
操作系统实验报告

操作系统

实验报告

实验一进程控制与描述

一、实验目的

通过对Windows 2000编程,进一步熟悉操作系统的基本概念,较好地理解Windows 2000的结构。通过创建进程、观察正在运行的进程和终止进程的程序设计和调试操作,进一步熟悉操作系统的进程概念,理解Windows 2000进程的“一生”。

二、实验环境

硬件环境:计算机一台,局域网环境;

软件环境:Windows 2000 Professional,Visual C++ 6.0专业版或企业版。

三、实验内容和步骤

第一部分:

Windows 2000 Professional下的GUI应用程序,使用Visual C++编译器创建一个GUI应用程序,代码中包括了WinMain()方法,该方法GUI类型的应用程序的标准入口点。

在“开始”菜单中单击“程序”-“附件”-“记事本”命令,将程序键入记事本中,并把代码保存为1-1.cpp。

程序1-1 Windows 2000的GUI应用程序

// msgbox项目

# include // 标准的include

// 告诉连接器与包括MessageBox API函数的user32库进行连接

# pragma comment(lib, “user32.lib” )

// 这是一个可以弹出信息框然后退出的筒单的应用程序

int APIENTRY WinMain(HINSTANCE /* hInstance */ ,

HINSTANCE /* hPrevInstance */ ,

LPSTR /* lpCmdLine */ ,

int /* nCmdShow */ )

{

:: MessageBox(

NULL, // 没有父窗口

“Hello, Windows 2000”, // 消息框中的文本

“Greetings”, // 消息框标题

MB_OK); // 其中只有一个OK按钮

// 返回0以便通知系统不进入消息循环

return(0) ;

}

也可以利用任何其他文本编辑器键入程序代码,如果这样,例如使用WORD来键入和编辑程序,则应该注意什么问题?

答:应该注意全角和半角字。

在“命令提示符”窗口运行CL.EXE,产生1-1.EXE文件:

C:\> CL 1-1.cpp

在程序1-1的GUI应用程序中,首先需要Windows.h头文件,以便获得传送给WinMain() 和MessageBox() API函数的数据类型定义。

接着的pragma指令指示编译器/连接器找到User32.LIB库文件并将其与产生的EXE文件连接起来。这样就可以运行简单的命令行命令CL MsgBox.CPP来创建这一应用程序,如果没有pragma指令,则MessageBox() API函数就成为未定义的了。这一指令是Visual Studio C++ 编译器特有的。

接下来是WinMain() 方法。其中有四个由实际的低级入口点传递来的参数。hInstance参数用来装入与代码相连的图标或位图一类的资源,无论何时,都可用GetModuleHandle() API函数将这些资源提取出来。系统利用实例句柄来指明代码和初始的数据装在内存的何处。句柄的数值实际上是EXE文件映像的基地址,通常为0x00400000。下一个参数hPrevInstance是为向后兼容而设的,现在系统将其设为NULL。应用程序的命令行(不包括程序的名称) 是lpCmdLine参数。另外,系统利用nCmdShow参数告诉应用程序如何显示它的主窗口(选项包括最小化、最大化和正常) 。

最后,程序调用MessageBox() API函数并退出。如果在进入消息循环之前就结束运行的话,最后必须返回0。

运行结果(试将其中的信息与程序3-1程序的运行结果进行比较) :

进程对象

操作系统将当前运行的应用程序看作是进程对象。利用系统提供的惟一的称为句柄(HANDLE) 的号码,就可与进程对象交互。这一号码只对当前进程有效。

本实验表示了一个简单的进程句柄的应用。在系统中运行的任何进程都可调用GetCurrentProcess() API函数,此函数可返回标识进程本身的句柄。然后就可在Windows需要该进程的有关情况时,利用这一句柄来提供。

程序1-2:获得和使用进程的句柄

// prochandle项目

# include

# include

// 确定自己的优先权的简单应用程序

void main()

{

// 从当前进程中提取句柄

HANDLE hProcessThis = :: GetCurrentProcess() ;

// 请求内核提供该进程所属的优先权类

DWORD dwPriority = :: GetPriorityClass(hProcessThis) ;

// 发出消息,为用户描述该类

std :: cout << “Current process priority: ” ;

switch(dwPriority)

{

case HIGH_PRIORITY_CLASS:

std :: cout << “High” ;

break;

case NORMAL_PRIORITY_CLASS:

std :: cout << “Normal” ;

break;

case IDLE_PRIORITY_CLASS:

std :: cout << “Idle” ;

break;

case REALTIME_PRIORITY_CLASS:

std :: co ut << “Realtime” ;

break;

default:

std :: cout << “” ;

break;

}

std :: cout << std :: endl;

}

程序1-2中列出的是一种获得进程句柄的方法。对于进程句柄可进行的惟一有用的操作是在API调用时,将其作为参数传送给系统,正如程序1-2中对GetPriorityClass() API函数的调用那样。在这种情况下,系统向进程对象内“窥视”,以决定其优先级,然后将此优先级返回给应用程序。

OpenProcess() 和CreateProcess() API函数也可以用于提取进程句柄。前者提取的是已经存在的进程的句柄,而后者创建一个新进程,并将其句柄提供出来。

在“命令提示符”窗口运行CL.EXE,产生1-2.EXE文件:

C:\> CL 1-2.cpp

运行结果:

将程序1-3.cpp程序键入记事本中,并把代码保存为1-3.cpp。

程序1-3显示如何找出系统中正在运行的所有进程,如何利用OpenProcess() API函数来获得每一个访问进程的进一步信息。

程序1-3 利用句柄查出进程的详细信息

// proclist项目

# include

# include

# include

// 当在用户模式机内核模式下都提供所耗时间时,在内核模式下进行所耗时间的64位计算的帮助方法DWORD GetKernelModePercentage(const FILETIME & ftKernel,

const FILETIME & ftUser)

{

// 将FILETIME结构转化为64位整数

ULONGLONG qwKernel =

( ( (ULONGLONG) ftKernel.dwHighDateTime) << 32) +

ftKernel.dwLowDateTime;

ULONGLONG qwUser =

( ( (ULONGLONG) ftUser.dwHighDateTime) << 32) +

ftUser.dwLowDateTime;

// 将消耗时间相加,然后计算消耗在内核模式下的时间百分比

ULONGLONG qwTotal = qwKernel + qwUser;

DWORD dwPct =

(DWORD) ( ( (ULONGLONG) 100*qwKernel) / qwTotal) ;

return(dwPct) ;

}

// 以下是将当前运行进程名和消耗在内核模式下的时间百分数都显示出来的应用程序

void main()

{

// 对当前系统中运行的进程拍取“快照”

HANDLE hSnapshot = :: CreateToolhelp32Snapshot(

TH32CS_SNAPPROCESS, // 提取当前进程

0) ; // 如果是当前进程,就将其忽略

// 初始化进程入口

PROCESSENTRY32 pe;

:: ZeroMemory(&pe, sizeof(pe) ) ;

pe.dwSize = sizeof(pe) ;

// 按所有进程循环

BOOL bMore = :: Process32First(hSnapshot, &pe) ;

while(bMore)

{

// 打开用于读取的进程

HANDLE hProcess = :: OpenProcess(

PROCESS_QUERY_INFORMA TION, // 指明要得到信息

FALSE, // 不必继承这一句柄

pe.th32ProcessID) ; // 要打开的进程

if (hProcess != NULL)

{

// 找出进程的时间

FILETIME ftCreation, ftExit, ftKernelMode, ftUserMode;

:: GetProcessTimes(

hProcess, // 所感兴趣的进程

&ftCreation, // 进程的启动时间(绝对的)

&ftExit, // 结束时间(如果有的话)

&ftKernelMode, // 在内核模式下消耗的时间

&ftUserMode) ; // 在用户模式下消耗的时间

// 计算内核模式消耗的时间百分比

DWORD dwPctKernel = :: GetKernelModePercentage(

ftKernelMode, // 在内核模式上消耗的时间

ftUserMode ) ; // 在用户模式下消耗的时间

// 向用户显示进程的某些信息

std :: cout << “Process ID: ” << pe.th32ProcessID

<< “, EXE file: ” << pe.szExeFile

<< “, % in kernel mode: ” << dwPctKernel

<< std :: endl;

// 消除句柄

:: CloseHandle(hProcess) ;

}

// 转向下一个进程

bMore = :: Process32Next(hSnapshot, &pe) ;

}

}

程序1-3程序首先利用Windows 2000的新特性,即工具帮助库来获得当前运行的所有进程的快照。然后应用程序进入快照中的每一个进程,得到其以PROCESSENTRY32结构表示的属性。这一结构用来向OpenProcess() API函数提供进程的ID。Windows跟踪每一进程的有关时间,示例中是通过打开的进程句柄和GetProcessTimes() API来直询得到有关时间的。接下来,一个定制的帮助函数取得了几个返回的数值,然后计算进程在内核模式下消耗的时间占总时间的百分比。程序的其余部分比较简单,只是将有关信息显示给用户,清除进程句柄,然后继续循环,直到所有进程都计算过为止。

在“命令提示符”窗口运行CL.EXE,产生1-3.EXE文件:

C:\> CL 1-3.cpp

运行结果:

第二部分:进程的“一生”

1、创建进程

创建子进程

// proccreate项目

# include

# include

# include

// 创建传递过来的进程的克隆过程并赋于其ID值

void StartClone(int nCloneID)

{

// 提取用于当前可执行文件的文件名

TCHAR szFilename[MAX_PA TH] ;

:: GetModuleFileName(NULL, szFilename, MAX_PA TH) ;

// 格式化用于子进程的命令行并通知其EXE文件名和克隆ID

TCHAR szCmdLine[MAX_PA TH] ;

:: sprintf(szCmdLine, “\”%s\” %d”, szFilename, nCloneID) ;

// 用于子进程的STARTUPINFO结构

STARTUPINFO si;

:: ZeroMemory(reinterpret_cast (&si) , sizeof(si) ) ;

si.cb = sizeof(si) ; // 必须是本结构的大小

// 返回的用于子进程的进程信息

PROCESS_INFORMA TION pi;

// 利用同样的可执行文件和命令行创建进程,并赋于其子进程的性质

BOOL bCreateOK = :: CreateProcess(

szFilename, // 产生这个EXE的应用程序的名称

szCmdLine, // 告诉其行为像一个子进程的标志

NULL, // 缺省的进程安全性

NULL, // 缺省的线程安全性

FALSE, // 不继承句柄

CREA TE_NEW_CONSOLE, // 使用新的控制台

NULL, // 新的环境

NULL, // 当前目录

&si, // 启动信息

&pi) ; // 返回的进程信息

// 对子进程释放引用

if (bCreateOK)

{

:: CloseHandle(pi.hProcess) ;

:: CloseHandle(pi.hThread) ;

}

}

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

{

// 确定进程在列表中的位置

int nClone(0) ;

if (argc > 1)

{

// 从第二个参数中提取克隆ID

:: sscanf(argv[1] , “%d” , &nClone) ;

}

// 显示进程位置

std :: cout << “Process ID: “ << :: GetCurrentProcessId()

<< “, Clone ID: “ << nClone

<< std :: endl;

// 检查是否有创建子进程的需要

const int c_nCloneMax = 25;

if (nClone < c_nCloneMax)

{

// 发送新进程的命令行和克隆号

StartClone(++nClone) ;

}

// 在终止之前暂停一下(l/2秒)

:: Sleep(500) ;

return 0;

}

本程序展示的是一个简单的使用CreateProcess() API函数的例子。首先形成简单的命令行,提供当前的EXE文件的指定文件名和代表生成克隆进程的号码。大多数参数都可取缺省值,但是创建标志参数使用了:

__

_CREATE_NEW_CONSOLE___________________________________________________________

___________

标志,指示新进程分配它自己的控制台,这使得运行示例程序时,在任务栏上产生许多活动标记。然后该克隆进程的创建方法关闭传递过来的句柄并返回main() 函数。在关闭程序之前,每一进程的执行主线程暂停一下,以便让用户看到其中的至少一个窗口。

CreateProcess() 函数有_____10___个核心参数?本实验程序中设置的各个参数的值是:

a. __________ szFilename _______________________________________;

b. __________ szCmdLine_______________________________________;

c. __________ NULL _______________________________________;

d. _________ FALSE ________________________________________;

e. __________ CREATE_NEW_CONSO_______________________________________;

程序运行时屏幕显示的信息是:

_

正在运行的进程

使用进程和操作系统的版本信息

// version项目

# include

# include

// 利用进程和操作系统的版本信息的简单示例

void main()

{

// 提取这个进程的ID号

DWORD dwIdThis = :: GetCurrentProcessId() ;

// 获得这一进程和报告所需的版本,也可以发送0以便指明这一进程

DWORD dwVerReq = :: GetProcessVersion(dwIdThis) ;

WORD wMajorReq = (WORD) (dwVerReq > 16) ;

WORD wMinorReq = (WORD) (dwVerReq & 0xffff) ;

std :: cout << "Process ID: " << dwIdThis

<< ", requires OS: " << wMajorReq << wMinorReq << std :: endl ;

// 设置版本信息的数据结构,以便保存操作系统的版本信息

OSVERSIONINFOEX osvix;

:: ZeroMemory(&osvix, sizeof(osvix) ) ;

osvix.dwOSVersionInfoSize = sizeof(osvix) ;

// 提取版本信息和报告

:: GetVersionEx(reinterpret_cast < LPOSVERSIONINFO > (&osvix) ) ;

std :: cout << "Running on OS: " << osvix.dwMajorVersion << "."

<< osvix.dwMinorVersion << std :: endl;

// 如果是NTS (Windows 2000) 系统,则提高其优先权

if (osvix.dwPlatformId == VER_PLA TFORM_WIN32_NT &&

osvix.dwMajorVersion >= 5)

{

// 改变优先级

:: SetPriorityClass(

:: GetCurrentProcess() , // 利用这一进程

HIGH_PRIORITY_CLASS) ; // 改变为high

// 报告给用户

std :: cout << "Task Manager should now now indicate this"

"process is high priority." << std :: endl;

}

}

运行结果:

当前PID信息:____8021__________________________________________________

当前操作系统版本:___6.1_______________________________________________

系统提示信息:_ Task Manager should now now indicate thisprocess is high priority.

程序向读者表明了如何获得当前的PID和所需的进程版本信息。为了运行这一程序,系统处理了所有的版本不兼容问题。

接着,程序演示了如何使用GetVersionEx() API函数来提取OSVERSIONINFOEX结构。这一数据块中包括了操作系统的版本信息。其中,“OS : 5.0”表示当前运行的操作系统是:______________Microsofwindows2000 5.0________________________________________________ 最后一段程序利用了操作系统的版本信息,以确认运行的是Windows 2000。代码接着将当前进程的优先级提高到比正常级别高。

单击Ctrl + Alt + Del键,进入“Windows任务管理器”,在“应用程序”选项卡中右键单击本任务,在快捷菜单中选择“转到进程”命令。

在“Windows任务管理器”的“进程”选项卡中,与本任务对应的进程映像名称是(为什么?) :_________vcspawn.exe____________________________________________ 右键单击该进程名,在快捷菜单中选择“设置优先级”命令,可以调整该进程的优先级,如设置为“高”后重新运行程序,屏幕显示有变化吗?为什么?

无,PID与优先级无关

终止进程

指令其子进程来“杀掉”自己的父进程

// procterm项目

# include

# include

# include

static LPCTSTR g_szMutexName = "w2kdg.ProcTerm.mutex.Suicide" ;

// 创建当前进程的克隆进程的简单方法

void StartClone()

{

// 提取当前可执行文件的文件名

TCHAR szFilename [MAX_PA TH] ;

:: GetModuleFileName(NULL, szFilename, MAX_PATH) ;

// 格式化用于子进程的命令行,指明它是一个EXE文件和子进程

TCHAR szCmdLine[MAX_PA TH] ;

:: sprintf(szCmdLine,"\"%s\"child",szFilename) ;

// 子进程的启动信息结构

STARTUPINFO si;

:: ZeroMemory(reinterpret_cast < void* > (&si) , sizeof(si) ) ;

si.cb = sizeof(si) ; // 应当是此结构的大小

// 返回的用于子进程的进程信息

PROCESS_INFORMA TION pi;

// 用同样的可执行文件名和命令行创建进程,并指明它是一个子进程

BOOL bCreateOK = :: CreateProcess(

szFilename, // 产生的应用程序名称(本EXE文件)

szCmdLine, // 告诉我们这是一个子进程的标志

NULL, // 用于进程的缺省的安全性

NULL, // 用于线程的缺省安全性

FALSE, // 不继承句柄

CREA TE_NEW_CONSOLE, // 创建新窗口,使输出更直观

NULL, // 新环境

NULL, // 当前目录

&si, // 启动信息结构

&pi ) ; // 返回的进程信息

// 释放指向子进程的引用

if (bCreateOK)

{

:: CloseHandle(pi.hProcess) ;

:: CloseHandle(pi.hThread) ;

}

}

void Parent()

{

// 创建"自杀"互斥程序体

HANDLE hMutexSuicide = :: CreateMutex(

NULL, // 缺省的安全性

TRUE, // 最初拥有的

g_szMutexName) ; // 为其命名

if (hMutexSuicide != NULL)

{

// 创建子进程

std :: cout << "Creating the child process." << std :: endl;

:: StartClone() ;

// 暂停

:: Sleep(5000) ;

// 指令子进程"杀"掉自身

std :: cout << "Telling the child process to quit. " << std :: endl;

:: ReleaseMutex(hMutexSuicide) ;

// 消除句柄

:: CloseHandle(hMutexSuicide) ;

}

}

void Child()

{

// 打开"自杀"互斥体

HANDLE hMutexSuicide = :: OpenMutex(

SYNCHRONIZE, // 打开用于同步

FALSE, // 不需要向下传递

g_szMutexName) ; // 名称

if (hMutexSuicide != NULL)

{

// 报告正在等待指令

std :: cout << "Child waiting for suicide instructions. " << std :: endl;

:: WaitForSingleObject(hMutexSuicide, INFINITE) ;

// 准备好终止,清除句柄

std :: cout << "Child quiting. " << std :: endl;

:: CloseHandle(hMutexSuicide) ;

}

}

int main(int arqc, char* argv[] )

{

// 决定其行为是父进程还是子进程

if (arqc > 1 && :: strcmp(argv[1],"child" )==0)

{

Child() ;

}

else

{

Parent() ;

}

return 0;

}

程序说明了一个进程从“生”到“死”的整个一生。第一次执行时,它创建一个子进程,其行为如同“父亲”。在创建子进程之前,先创建一个互斥的内核对象,其行为对于子进程来说,如同一个“自杀弹”。当创建子进程时,就打开了互斥体并在其他线程中进行别的处理工作,同时等待着父进程使用ReleaseMutex() API发出“死亡”信号。然后用Sleep() API调用来模拟父进程处理其他工作,等完成时,指令子进程终止。

当调用ExitProcess() 时要小心,进程中的所有线程都被立刻通知停止。在设计应用程序时,必须让主线程在正常的C++ 运行期关闭(这是由编译器提供的缺省行为) 之后来调用这一函数。当它转向受信状态时,通常可创建一个每个活动线程都可等待和停止的终止事件。

在正常的终止操作中,进程的每个工作线程都要终止,由主线程调用ExitProcess()。接着,管理层对进程增加的所有对象释放引用,并将用GetExitCodeProcess() 建立的退出代码从STILL_ACTIVE改变为在ExitProcess() 调用中返回的值。最后,主线程对象也如同进程对象一样转变为受信状态。

等到所有打开的句柄都关闭之后,管理层的对象管理器才销毁进程对象本身。还没有一种函数可取得终止后的进程对象为其参数,从而使其“复活”。当进程对象引用一个终止了的对象时,有好几个API函数仍然是有用的。进程可使用退出代码将终止方式通知给调用GetExitCodeProcess() 的其他进程。同时,GetProcessTimes() API函数可向主调者显示进程的终止时间。

运行结果:

1)第一次执行时 它创建一个子进程 其行为如同“父亲”

表示:Creating the child process.

2)用Sleep() API调用来模拟父进程处理其他工作 等完成时 指令子进程终止。

表示:Telling the child process to quit_________

在熟悉源代码的基础上,利用本实验介绍的API函数来尝试改进本程序(例如使用GetProcessTimes() API函数) 并运行。请描述你所做的工作:

GetProcessTimes() API 可向主调者显示进程终止时间

四、实验总结

请总结一下本次实验的收获、教训和感受,结合课本内容谈一下你对进程的理解。

对进程有了更多的了解比如:

进程具有的特征:结构特征、动态性、并发性、独立性和异步性。

对于进程的定义可以从不同的角度来说,其中较为典型的定义有:

1、进程是程序的一次执行;

2、进程是一个程序及其数据在处理机上顺序执行时发生的活动;

3、进程是程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单

位。

对于传统os中的进程定义为:进程是进程实体的运行过程,使系统进行资源分配和调度的一个独立单位。

进程有三种基本状态:就绪状态、执行状态、阻塞状态。

创建一个进程:

1、申请空白的PCB ;

2、为进城分配资源;

3、初始化进程控制块;

4、将进程插入就绪队列。

终止一个进程:

1、根据被终止进程的标识符,PCB集合中检索出该进程的PCB,从中读出该进程的状态;

2、若终止进程正处于执行状态,应立即中止该进程的执行,并置调度标志为真,用于指示该进程被终止进程的后应该重新进行调度;

3、若该进程还有子孙进程,还应该将其所有的子孙进程终止,以防止他们成为不可控的进程。

4、将终止进程所拥有的全部资源,或者归还给其父进程,或者归还给系统;

5、将终止进程PCB从所在队列中移除,等待其他程序来搜索信,通过实验更清楚的了解了进程,理解了进程的创建过程和终止过程;

实验二Windows2000线程的运行

一、背景知识

Windows 2000是一个抢先式多任务操作系统,提供了对多线程进程的支持。这样开发人员可以创建一种应用程序,将必须完成的工作任务划分为逻辑小块,而将每个小块任务再分配给线程来完成。

创建新进程施,同时创建该进程的主线程,线程对象句柄可从CreateProcess()的参数中返回,进程对象的创建过程就是主线程对象的创建过程。

线程执行涉及的API函数有:

线程创建函数:CreateThread()

获得线程优先级函数:GetThreadPriority()

设置线程优先级函数:SetThreadPriority()

判断线程当前是否处于运行状态函数:GetExitCodeThread()

获得线程标识符函数:GetCurrentThreadID()

ResumeThread()

用于挂起线程的函数:SuspendThread()

终止线程函数:ExitThread()

终止线程函数:TerminateThread()

各函数的用法见实验例程或在MSDN中查询。

二、实验目的

在本实验中,通过对线程创建、改变线程优先级及线程的启动与停止等方法的了解,来加深对Windows 2000线程控制与管理的理解。

三、实验内容与步骤

程序3_1、创建新线程。

//创建线程的文件Thread1.cpp

#include

#include

#include

class CWorkerThread //封装创建工作线程的类。

{ public:

CWorkerThread(LPCTSTR szName):

m_szName(szName),m_hThread(INV ALID_HANDLE_V ALUE)

{

m_hThread=CreateThread( //创建新线程并令其启动。

NULL, // 默认的安全性。

0, //默认堆栈。

ThreadProc, // 类范围内的线程。

reinterpret_cast(this), //发送给线程的参数——指向该类的指针。

0, // 线程创建后立即执行。

NULL); //不需要返回线程参数。

}

virtual ~CWorkerThread() {CloseHandle(m_hThread);}

virtual void WaitForCompletion() //等待完成的方法。

{ WaitForSingleObject(m_hThread,INFINITE); }

protected:

static DWORD WINAPI ThreadProc(LPVOID lpParam)

{

CWorkerThread * pThis=reinterpret_cast(lpParam);

pThis_>DoStuff();

return(0); //从线程中退出

}

virtual void DoStuff() //重复发送线程的ID和名称

{for(int n=0;n<1000;++n)

printf("Thread %s ID:%d,count %d\n",m_szName,GetCurrentThreadId(),n);

}

protected:

HANDLE m_hThread; //指向线程内核对象的指针

LPCTSTR m_szName; //保存线程名称

};

void main()

{

CWorkerThread wtA("A"); //创建两个线程,名称分别为A和B

CWorkerThread wtB("B");

wtA.WaitForCompletion(); //暂停,直到两者都完成为止

wtB.WaitForCompletion();

printf("Both threads complete.\n");//报告线程完成

}

结果:

程序3_2、改变线程的优先级

//创建线程的文件Thread2.cpp

#include

#include

#include

class CWorkerThread //封装创建工作线程的类。

{ public:

CWorkerThread(LPCTSTR szName):

m_szName(szName),m_hThread(INV ALID_HANDLE_V ALUE)

{

m_hThread=CreateThread( //创建新线程并令其启动。

NULL, // 默认的安全性。

0, //默认堆栈。

ThreadProc, // 类范围内的线程。

reinterpret_cast(this), //发送给线程的参数——指向该类的指针。

0, // 线程创建后立即执行。

NULL); //不需要返回线程参数。

}

virtual ~CWorkerThread() {CloseHandle(m_hThread);}

virtual void WaitForCompletion() //等待完成的方法。

{ WaitForSingleObject(m_hThread,INFINITE); }

// 改变线程的优先级

virtual void SetPriority(int nPriority)

{ SetThreadPriority(m_hThread,nPriority);}

protected:

static DWORD WINAPI ThreadProc(LPVOID lpParam)

{//

CWorkerThread * pThis=reinterpret_cast(lpParam);

pThis_>DoStuff();

return(0); //从线程中退出

}

virtual void DoStuff() //重复发送线程的ID和名称

{for(int n=0;n<1000;++n)

printf("Thread %s ID:%d,count %d\n",m_szName,GetCurrentThreadId(),n);

}

protected:

HANDLE m_hThread; //指向线程内核对象的指针

LPCTSTR m_szName; //保存线程名称

};

void main()

{

CWorkerThread wtA("A"); //创建两个线程,名称分别为A和B

CWorkerThread wtB("B");

wtA.SetPriority(THREAD_PRIORITY_LOWEST); //使线程A的优先级尽可能低wtA.WaitForCompletion(); //暂停,直到两者都完成为止

wtB.WaitForCompletion();

printf("Both threads complete.\n"); //报告线程完成

}

结果:

程序3_3、启动和停止线程

#include

#include

#include

class CWorkerThread

{public:

CWorkerThread(LPCTSTR szName):

m_szName(szName),m_hThread(INV ALID_HANDLE_V ALUE)

{

m_hThread=CreateThread(

NULL,0,ThreadProc,reinterpret_cast(this),0,NULL);

}

virtual ~CWorkerThread(){CloseHandle(m_hThread);}

virtual void WaitForCompletion()

{ WaitForSingleObject(m_hThread,INFINITE);}

virtual void SetPriority(int nPriority)

{ SetThreadPriority(m_hThread,nPriority);}

virtual void Suspend()

{ SuspendThread(m_hThread);}

virtual void Resume()

{ ResumeThread(m_hThread);}

protected:

static DWORD WINAPI ThreadProc(LPVOID lpParam)

{

CWorkerThread * pThis=reinterpret_cast(lpParam);

pThis_>DoStuff();

return(0);

}

virtual void DoStuff()

{for(int n=0;n<10;++n)

printf("Thread %s ID:%d,count %d\n",m_szName,GetCurrentThreadId(),n);

}

protected:

HANDLE m_hThread;

LPCTSTR m_szName;

};

void main()

{CWorkerThread wtA("A");

CWorkerThread wtB("B");

wtA.SetPriority(THREAD_PRIORITY_LOWEST);

wtB.Suspend();

wtA.WaitForCompletion();

wtB.Resume();

wtB.WaitForCompletion();

printf("Both threads complete.\n");

}

结果:

阅读、调试、运行、分析程序,并回答如下问题:

1)写出上述三个程序的运行结果 (分行书写。如果运行不成功,则可能的原因是什么?) ,这个结果与你期望的一致吗?(从进程并发的角度对结果进行分析)

程序下面已经写出,请见程序截图。

2) 根据输出结果,对照分析程序,请简单描述各程序运行的流程。

答:流程是,封装创建工作线程的类,创建新线程并令其启动,线程创建后立即执行从线程中退/创建两个线程,名称分别为A和B,出报告线程完成。

封装创建工作线程的类,创建新线程并令其启动,线程创建后立即执行从线程中退/创建两个线程,名称分别为A和B,使线程A的优先级尽可能低出报告线程完成。

四、实验总结

在这次实验中,我对线程有了一些了解,通过对线程创建、改变线程优先级及线程的启动与停止等了解线程的管理和控制。线程是为了进一步提高程序的并行程度和系统资源利用率,人们提出的新概念。一个进程内部可以包含多个并发的线程,线程成为处理机调度的基本单位。每个线程被创建后,便可与其他线程一起并发的执行,并发运行的线程间也存在着共享资源和相互合作的制约关系,致使线程在运行时也具有间断性。线程执行完后正常终止,也可能因出现错误或其他某种原因而被强行终止。

创建线程:应用程序在启动时,通常仅有一个线程在执行,该线程被称为“初始化线程”,它可根据需要再去创建若干个线程。在创建新线程时,需要利用一个线程创建函数CreateThread (),并提供相应的参数。在线程创建函数执行完后,将会返回一个线程标识符供以后使用。

终止进程:一种方法是再线程完成了自己的工作后自愿退出:另一种是线程在运行中出现错误或由于某种原因而被其他线程强行终止。线程被终止后并不立即释放它所占有的资源,只有

当进程中的其他线程执行了分离函数后,被终止的线程才与资源分离,此时的资源才能呗其他线程利用。虽已被终止但尚未释放资源的线程,仍可以被需要它的线程所利用,以使被终止线程重新恢复运行。

实验三并发与调度

一、实验目的

在本实验中,通过对事件和互斥体对象的了解,来加深对Windows 2000线程同步的理解。通过分析实验程序,了解管理事件对象的API。了解在进程中如何使用事件对象,在进程中如何使用互斥体对象,线程如何通过文件映射对象发送数据。

二、实验环境

硬件环境:计算机一台,局域网环境;

软件环境:Windows 2000 Professional,Visual C++ 6.0专业版或企业版。

三、实验内容和步骤

第一部分:互斥体对象

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

1、利用互斥体保护共享资源

// mutex项目

# include

# include

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

class CCountUpDown

{

public:

// 创建者创建两个线程来访问共享值

CCountUpDown(int nAccesses) :

m_hThreadInc(INV ALID_HANDLE_V ALUE) ,

m_hThreadDec(INV ALID_HANDLE_V ALUE) ,

m_hMutexValue(INV ALID_HANDLE_V ALUE) ,

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

}

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

virtual ~CCountUpDown()

{

:: CloseHandle(m_hThreadInc) ;

:: CloseHandle(m_hThreadDec) ;

:: CloseHandle(m_hMutexValue) ;

}

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

virtual void WaitForCompletion()

{

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

if (m_hThreadInc != INVALID_HANDLE_V ALUE &&

m_hThreadDec != INVALID_HANDLE_V ALUE)

{

// 等待两者完成(顺序并不重要)

:: 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(1000); // 使显示速度放慢

// 释放对数值的访问

:: ReleaseMutex(m_hMutexValue) ;

}

}

static DWORD WINAPI IncThreadProc(LPVOID lpParam)

{

// 将参数解释为'this' 指针

CCountUpDown* pThis =

reinterpret_cast < CCountUpDown* > (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() ; }

分析程序的运行结果,可以看到线程 (加和减线程) 的交替执行 (因为Sleep() API 允许Windows 切换线程) 。在每次运行之后,数值应该返回初始值 (0) ,因为在每次运行之后写入线程在等待队列中变成最后一个,内核保证它在其他线程工作时不会再运行。

1) 请描述运行结果 (

如果运行不成功,则可能的原因是什么?) :

______________________________________________________

2)

线程 (加和减线程) 的交替执行 (因为Sleep() API 允许Windows 切换线程) 。在每次运行之后,数值应该返回初始值 (0) ,因为在每次运行之后写入线程在等待队列中变成最后一个,内核保证它在其他线程工作时不会再运行。

第二部分 经典同步问题的实现 实验内容与步骤

1.利用信号量来实现多个生产者—消费者问题。 2.利用Windows2000同步机制来实现哲学家进餐问题。 3. 利用Windows2000同步机制来实现读者—写者问题。 阅读并分析参考程序,给出运算结果

1. 生产者—消费者问题

# include # include # include const num=10;

volatile int in=0,out=0; int buf[5]={0,0,0,0,0};

HANDLE mutex,empty,full;

static DWORD WINAPI Threadp(LPVOID lp) {

LONG np=reinterpret_cast(lp); Sleep(np*10);

LONG item=np+100;

操作系统实验报告--实验一--进程管理

实验一进程管理 一、目的 进程调度是处理机管理的核心内容。本实验要求编写和调试一个简单的进程调度程序。通过本实验加深理解有关进程控制块、进程队列的概念,并体会和了解进程调度算法的具体实施办法。 二、实验内容及要求 1、设计进程控制块PCB的结构(PCB结构通常包括以下信息:进程名(进程ID)、进程优先数、轮转时间片、进程所占用的CPU时间、进程的状态、当前队列指针等。可根据实验的不同,PCB结构的内容可以作适当的增删)。为了便于处理,程序中的某进程运行时间以时间片为单位计算。各进程的轮转时间数以及进程需运行的时间片数的初始值均由用户给定。 2、系统资源(r1…r w),共有w类,每类数目为r1…r w。随机产生n进程P i(id,s(j,k),t),0<=i<=n,0<=j<=m,0<=k<=dt为总运行时间,在运行过程中,会随机申请新的资源。 3、每个进程可有三个状态(即就绪状态W、运行状态R、等待或阻塞状态B),并假设初始状态为就绪状态。建立进程就绪队列。 4、编制进程调度算法:时间片轮转调度算法 本程序用该算法对n个进程进行调度,进程每执行一次,CPU时间片数加1,进程还需要的时间片数减1。在调度算法中,采用固定时间片(即:每执行一次进程,该进程的执行时间片数为已执行了1个单位),这时,CPU时间片数加1,进程还需要的时间片数减1,并排列到就绪队列的尾上。 三、实验环境 操作系统环境:Windows系统。 编程语言:C#。 四、实验思路和设计 1、程序流程图

2、主要程序代码 //PCB结构体 struct pcb { public int id; //进程ID public int ra; //所需资源A的数量 public int rb; //所需资源B的数量 public int rc; //所需资源C的数量 public int ntime; //所需的时间片个数 public int rtime; //已经运行的时间片个数 public char state; //进程状态,W(等待)、R(运行)、B(阻塞) //public int next; } ArrayList hready = new ArrayList(); ArrayList hblock = new ArrayList(); Random random = new Random(); //ArrayList p = new ArrayList(); int m, n, r, a,a1, b,b1, c,c1, h = 0, i = 1, time1Inteval;//m为要模拟的进程个数,n为初始化进程个数 //r为可随机产生的进程数(r=m-n) //a,b,c分别为A,B,C三类资源的总量 //i为进城计数,i=1…n //h为运行的时间片次数,time1Inteval为时间片大小(毫秒) //对进程进行初始化,建立就绪数组、阻塞数组。 public void input()//对进程进行初始化,建立就绪队列、阻塞队列 { m = int.Parse(textBox4.Text); n = int.Parse(textBox5.Text); a = int.Parse(textBox6.Text); b = int.Parse(textBox7.Text); c = int.Parse(textBox8.Text); a1 = a; b1 = b; c1 = c; r = m - n; time1Inteval = int.Parse(textBox9.Text); timer1.Interval = time1Inteval; for (i = 1; i <= n; i++) { pcb jincheng = new pcb(); jincheng.id = i; jincheng.ra = (random.Next(a) + 1); jincheng.rb = (random.Next(b) + 1); jincheng.rc = (random.Next(c) + 1); jincheng.ntime = (random.Next(1, 5)); jincheng.rtime = 0;

操作系统实验报告一

重庆大学 学生实验报告 实验课程名称操作系统原理 开课实验室DS1501 学院软件学院年级2013专业班软件工程2 班学生姓名胡其友学号20131802 开课时间2015至2016学年第一学期 总成绩 教师签名洪明坚 软件学院制

《操作系统原理》实验报告 开课实验室:年月日学院软件学院年级、专业、班2013级软件工 程2班 姓名胡其友成绩 课程名称操作系统原理 实验项目 名称 指导教师洪明坚 教师 评语教师签名:洪明坚年月日 1.实验目的: ?进入实验环境 –双击expenv/setvars.bat ?检出(checkout)EPOS的源代码 –svn checkout https://www.doczj.com/doc/d77814390.html,/svn/epos ?编译及运行 –cd epos/app –make run ?清除所有的临时文件 –make clean ?调试 –make debug ?在“Bochs Enhanced Debugger”中,输入“quit”退出调试 –调试指令,请看附录A 2.实验内容: ?编写系统调用“time_t time(time_t *loc)” –功能描述 ?返回从格林尼治时间1970年1月1日午夜起所经过的秒数。如果指针loc 非NULL,则返回值也被填到loc所指向的内存位置 –数据类型time_t其实就是long ?typedef long time_t; 3.实验步骤: ?Kernel space –K1、在machdep.c中,编写系统调用的实现函数“time_t sys_time()”,计算用户秒数。需要用到 ?变量g_startup_time,它记录了EPOS启动时,距离格林尼治时间1970年1午夜的秒数 ?变量g_timer_ticks

操作系统实验报告

操作系统实验报告 ' 学号: 姓名: 指导老师: 完成日期: ~

目录 实验一 (1) 实验二 (2) 实验三 (7) 实验四 (10) 实验五 (15) 实验六 (18) 实验七 (22) \

实验一 UNIX/LINUX入门 一、实验目的 了解 UNIX/LINUX 运行环境,熟悉UNIX/LINUX 的常用基本命令,熟悉和掌握UNIX/LINUX 下c 语言程序的编写、编译、调试和运行方法。 二、实验内容 熟悉 UNIX/LINUX 的常用基本命令如ls、who、pwd、ps 等。 练习 UNIX/LINUX的文本行编辑器vi 的使用方法 熟悉 UNIX/LINUX 下c 语言编译器cc/gcc 的使用方法。用vi 编写一个简单的显示“Hello,World!”c 语言程序,用gcc 编译并观察编译后的结果,然后运行它。 三、实验要求 按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。 四、实验程序 #include <> #include <> int main() { printf ("Hello World!\n"); return 0; } 五、实验感想 通过第一次室验,我了解 UNIX/LINUX 运行环境,熟悉了UNIX/LINUX 的常用基本命令,熟悉和掌握了UNIX/LINUX 下c 语言程序的编写、编译、调试和运行方法。

实验二进程管理 一、实验目的 加深对进程概念的理解,明确进程与程序的区别;进一步认识并发执行的实质。 二、实验内容 (1)进程创建 编写一段程序,使用系统调用fork()创建两个子进程。当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示“a“;子进程分别显示字符”b“和字符“c”。试观察记录屏幕上的显示结果,并分析原因。 (2)进程控制 修改已编写的程序,将每一个进程输出一个字符改为每一个进程输出一句话,再观察程序执行时屏幕上出现的现象,并分析原因。 (3)进程的管道通信 编写程序实现进程的管道通信。使用系统调用pipe()建立一个管道,二个子进程P1 和P2 分别向管道各写一句话: Child 1 is sending a message! Child 2 is sending a message! 父进程从管道中读出二个来自子进程的信息并显示(要求先接收P1,再接收P2)。 三、实验要求 按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。 四、实验设计 1、功能设计 (1)进程创建 使用fork()创建两个子进程,父进程等待两个子进程执行完再运行。 (2)进程控制 使用fork()创建两个子进程,父进程等待两个子进程分别输出一句话再运行。 (3)进程的管道通信 先创建子进程1,向管道写入一句话,子进程1结束后创建子进程2,向管道写入一句话,最后父进程从管道中读出。 2、数据结构 子进程和管道。 3、程序框图

嵌入式操作系统实验报告

中南大学信息科学与工程学院实验报告 姓名:安磊 班级:计科0901 学号: 0909090310

指导老师:宋虹

目录 课程设计内容 ----------------------------------- 3 uC/OS操作系统简介 ------------------------------------ 3 uC/OS操作系统的组成 ------------------------------ 3 uC/OS操作系统功能作用 ---------------------------- 4 uC/OS文件系统的建立 ---------------------------- 6 文件系统设计的原则 ------------------------------6 文件系统的层次结构和功能模块 ---------------------6 文件系统的详细设计 -------------------------------- 8 文件系统核心代码 --------------------------------- 9 课程设计感想 ------------------------------------- 11 附录-------------------------------------------------- 12

课程设计内容 在uC/OS操作系统中增加一个简单的文件系统。 要求如下: (1)熟悉并分析uc/os操作系统 (2)设计并实现一个简单的文件系统 (3)可以是存放在内存的虚拟文件系统,也可以是存放在磁盘的实际文件系统 (4)编写测试代码,测试对文件的相关操作:建立,读写等 课程设计目的 操作系统课程主要讲述的内容是多道操作系统的原理与技术,与其它计算机原理、编译原理、汇编语言、计算机网络、程序设计等专业课程关系十分密切。 本课程设计的目的综合应用学生所学知识,建立系统和完整的计算机系统概念,理解和巩固操作系统基本理论、原理和方法,掌握操作系统开发的基本技能。 I.uC/OS操作系统简介 μC/OS-II是一种可移植的,可植入ROM的,可裁剪的,抢占式的,实时多任务操作系统内核。它被广泛应用于微处理器、微控制器和数字信号处理器。 μC/OS 和μC/OS-II 是专门为计算机的嵌入式应用设计的,绝大部分代码是用C语言编写的。CPU 硬件相关部分是用汇编语言编写的、总量约200行的汇编语言部分被压缩到最低限度,为的是便于移植到任何一种其它的CPU 上。用户只要有标准的ANSI 的C交叉编译器,有汇编器、连接器等软件工具,就可以将μC/OS-II嵌入到开发的产品中。μC/OS-II 具有执行效率高、占用空间小、实时性能优良和可扩展性强等特点,最小内核可编译至2KB 。μC/OS-II 已经移植到了几乎所有知名的CPU 上。 严格地说uC/OS-II只是一个实时操作系统内核,它仅仅包含了任务调度,任务管理,时间管理,内存管理和任务间的通信和同步等基本功能。没有提供输入输出管理,文件系统,网络等额外的服务。但由于uC/OS-II良好的可扩展性和源码开放,这些非必须的功能完全 可以由用户自己根据需要分别实现。 uC/OS-II目标是实现一个基于优先级调度的抢占式的实时内核,并在这个内核之上提供最基本的系统服务,如信号量,邮箱,消息队列,内存管理,中断管理等。 uC/OS操作系统的组成 μC/OS-II可以大致分成核心、任务处理、时间处理、任务同步与通信,CPU的移植等5个部分。如下图:

操作系统实验报告4

《操作系统》实验报告 实验序号: 4 实验项目名称:进程控制

Printf(“child Complete”); CloseHandle(pi.hProcess); CloseHandle(pi hThread); ﹜ 修改后: #include #include int main(VOID) { STARTUPINFO si; PROCESS_INFORMA TION pi; ZeroMemory(&si,sizeof(si)); si.cb=sizeof(si); ZeroMemory(&pi,sizeof(pi)); if(!CreateProcess(NULL, "c:\\WINDOWS\\system32\\mspaint.exe", NULL, NULL, FALSE, 0, NULL, NULL, &si,&pi)) { fprintf(stderr,"Creat Process Failed"); return -1; } WaitForSingleObject(pi.hProcess,INFINITE); printf("child Complete"); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } 在“命令提示符”窗口运行CL命令产生可执行程序4-1.exe:C:\ >CL 4-1.cpp

实验任务:写出程序的运行结果。 4.正在运行的进程 (2)、编程二下面给出了一个使用进程和操作系统版本信息应用程序(文件名为4-5.cpp)。它利用进程信息查询的API函数GetProcessVersion()与GetVersionEx()的共同作用。确定运行进程的操作系统版本号。阅读该程序并完成实验任务。 #include #include

电大操作系统本科实验报告

中央广播电视大学计算机科学与技术专业操作系统(本科) 实验报告 院系:_______________ 班级:________ 学生姓名:_____________ 学号:______ 指导教师:________ 完成日期2015年月日

一、实验题目: Linux应用及shell编程 二、实验目的和要求: 目的 1.掌握Linux一般命令格式和常用命令。 2.学会使用vi编辑器建立、编辑文本文件。 3.了解shell的作用和主要分类。 4.学会bash脚本的建立和执行方式。 5.理解bash的基本语法。 6.学会编写简单的shell脚本。 要求 1.登录进入系统,修改个人密码。 2.使用简单命令:date,cal,who,echo,clear等,了解Linux命令格式。 3.进入vi。建立一个文件,如。进入插入方式,输入一个C语言程序的各行内容,故意制造几处错误。最后,将该文件存盘。回到shell状态下。 4.运行,编译该文件,会发现错误提示。理解其含义。 5.利用vi建立一个脚本文件,其中包括date,cal,pwd,ls等常用命令。然后以不同方式执行该脚本。 6.对主教材第2章中的适当例题进行编辑,然后执行。从而体会通配符、引号、输入输出重定向符、成组命令的作用;能正确使用自定义变量、位置参数、环境变量、输入/输出命令;能利用if语句、while语句、for语句和函数编写简单的脚本。 三、实验内容: 1.正确地登录和退出系统。 2.熟悉使用ls,cp,cat,等常用命令。 3.进入和退出vi。利用文本插入方式建立一个文件。

5.建立简单shell脚本并执行它。 四、实验技术和方法: Linux中各种脚本语言 五、实验环境: 虚拟机,ubuntuserver版,shell 六、实验步骤和结果: 1.正确地登录和退出系统。 使用exit命令退出系统 2.熟悉使用cat,cd,cp,ls,mor,rm,vi,who等常用命令。 2.使用vi编写 按:wq存储,并退出 5.建立shell脚本并执行它。 使用VI创建ex1文件,内容含三条命令date/pwd/cd.. 七、实验结果分析: 无 实训3 一、实验题目: 进程管理 二、实验目的和要求: 目的 1.加深对进程概念的理解,明确它与程序的区别,突出理解其动态性特征。

实时操作系统报告

实时操作系统课程实验报告 专业:通信1001 学号:3100601025 姓名:陈治州 完成时间:2013年6月11日

实验简易电饭煲的模拟 一.实验目的: 掌握在基于嵌入式实时操作系统μC/OS-II的应用中,基于多任务的模式的编程方法。锻炼综合应用多任务机制,任务间的通信机制,内存管理等的能力。 二.实验要求: 1.按“S”开机,系统进入待机状态,时间区域显示当前北京时间,默认模式“煮饭”; 2.按“C”选择模式,即在“煮饭”、“煮粥”和“煮面”模式中循环选择; 3.按“B”开始执行模式命令,“开始”状态选中,时间区域开始倒计时,倒计时完成后进入“保温”状态,同时该状态显示选中,时间区域显示保温时间; 4.按“Q”取消当前工作状态,系统进入待机状态,时间区域显示北京时间,模式为当前模式; 5.按“X”退出系统,时间区域不显示。 6.煮饭时长为30,煮粥时长为50,煮面时长为40. 三.实验设计: 1.设计思路: 以老师所给的五个程序为基础,看懂每个实验之后,对borlandc的操作有了大概的认识,重点以第五个实验Task_EX为框架,利用其中界面显示与按键扫描以及做出相应的响应,对应实现此次实验所需要的功能。 本次实验分为界面显示、按键查询与响应、切换功能、时钟显示与倒计时模块,综合在一起实验所需功能。 2.模块划分图: (1)界面显示: Main() Taskstart() Taskstartdispinit() 在TaskStartDispInit()函数中,使用PC_DispStr()函数画出界面。

(2)按键查询与响应: Main() Taskstart() 在TaskStart()函数中,用if (PC_GetKey(&key) == TRUE)判断是否有按键输入。然后根据key 的值,判断输入的按键是哪一个;在响应中用switch语句来执行对应按键的响应。 (3)切换功能: l计数“C”按 键的次数 M=l%3 Switch(m) M=0,1,2对应于煮饭,煮粥,煮面,然后使用PC_DispStr()函数在选择的选项前画上“@”指示,同时,在其余两项钱画上“”以“擦出”之前画下的“@”,注意l自增。 四.主要代码: #include "stdio.h" #include "includes.h" #include "time.h" #include "dos.h" #include "sys/types.h" #include "stdlib.h" #define TASK_STK_SIZE 512 #define N_TASKS 2 OS_STK TaskStk[N_TASKS][TASK_STK_SIZE]; OS_STK TaskStartStk[TASK_STK_SIZE]; INT8U TaskData[N_TASKS];

操作系统实验报告

操作系统教程 实 验 指 导 书 姓名: 学号: 班级:软124班 指导老师:郭玉华 2014年12月10日

实验一WINDOWS进程初识 1、实验目的 (1)学会使用VC编写基本的Win32 Consol Application(控制台应用程序)。 (2)掌握WINDOWS API的使用方法。 (3)编写测试程序,理解用户态运行和核心态运行。 2、实验内容和步骤 (1)编写基本的Win32 Consol Application 步骤1:登录进入Windows,启动VC++ 6.0。 步骤2:在“FILE”菜单中单击“NEW”子菜单,在“projects”选项卡中选择“Win32 Consol Application”,然后在“Project name”处输入工程名,在“Location”处输入工程目录。创建一个新的控制台应用程序工程。 步骤3:在“FILE”菜单中单击“NEW”子菜单,在“Files”选项卡中选择“C++ Source File”, 然后在“File”处输入C/C++源程序的文件名。 步骤4:将清单1-1所示的程序清单复制到新创建的C/C++源程序中。编译成可执行文件。 步骤5:在“开始”菜单中单击“程序”-“附件”-“命令提示符”命令,进入Windows“命令提示符”窗口,然后进入工程目录中的debug子目录,执行编译好的可执行程序: E:\课程\os课\os实验\程序\os11\debug>hello.exe 运行结果 (如果运行不成功,则可能的原因是什么?) : 有可能是因为DOS下路径的问题 (2)计算进程在核心态运行和用户态运行的时间 步骤1:按照(1)中的步骤创建一个新的“Win32 Consol Application”工程,然后将清单1-2中的程序拷贝过来,编译成可执行文件。 步骤2:在创建一个新的“Win32 Consol Application”工程,程序的参考程序如清单1-3所示,编译成可执行文件并执行。 步骤3:在“命令提示符”窗口中运行步骤1中生成的可执行文件,测试步骤2中可执行文件在核心态运行和用户态运行的时间。 E:\课程\os课\os实验\程序\os12\debug>time TEST.exe 步骤4:运行结果 (如果运行不成功,则可能的原因是什么?) : 因为程序是个死循环程序 步骤5:分别屏蔽While循环中的两个for循环,或调整两个for循环的次数,写出运行结果。 屏蔽i循环: 屏蔽j循环: _______________________________________________________________________________调整循环变量i的循环次数:

操作系统实验报告

操作系统实验报告 集团企业公司编码:(LL3698-KKI1269-TM2483-LUI12689-ITT289-

实验二进程调度1.目的和要求 通过这次实验,理解进程调度的过程,进一步掌握进程状态的转变、进程调度的策略,进一步体会多道程序并发执行的特点,并分析具体的调度算法的特点,掌握对系统性能的评价方法。 2.实验内容 阅读教材《计算机操作系统》第二章和第三章,掌握进程管理及调度相关概念和原理。 编写程序模拟实现进程的轮转法调度过程,模拟程序只对PCB进行相应的调度模拟操作,不需要实际程序。假设初始状态为:有n个进程处于就绪状态,有m个进程处于阻塞状态。采用轮转法进程调度算法进行调度(调度过程中,假设处于执行状态的进程不会阻塞),且每过t个时间片系统释放资源,唤醒处于阻塞队列队首的进程。 程序要求如下: 1)输出系统中进程的调度次序; 2)计算CPU利用率。 3.实验环境 Windows操作系统、VC++6.0 C语言 4设计思想: (1)程序中进程可用PCB表示,其类型描述如下:

structPCB_type { intpid;//进程名 intstate;//进程状态 2——表示“执行”状态 1——表示“就绪”状态 0——表示“阻塞”状态 intcpu_time;//运行需要的CPU时间(需运行的时间片个数) } 用PCB来模拟进程; (2)设置两个队列,将处于“就绪”状态的进程PCB挂在队列ready中;将处于“阻塞”状态的进程PCB挂在队列blocked中。队列类型描述如下: structQueueNode{ structPCB_typePCB; StructQueueNode*next; } 并设全程量: structQueueNode*ready_head=NULL,//ready队列队首指针 *ready_tail=NULL,//ready队列队尾指 针

操作系统实验报告心得体会

操作系统实验报告心得体会 每一次课程设计度让我学到了在平时课堂不可能学到的东西。所以我对每一次课程设计的机会都非常珍惜。不一定我的课程设计能够完成得有多么完美,但是我总是很投入的去研究去学习。所以在这两周的课设中,熬了2个通宵,生物钟也严重错乱了。但是每完成一个任务我都兴奋不已。一开始任务是任务,到后面任务就成了自己的作品了。总体而言我的课设算是达到了老师的基本要求。总结一下有以下体会。 1、网络真的很强大,用在学习上将是一个非常高效的助手。几乎所有的资料都能够在网上找到。从linux虚拟机的安装,到linux的各种基本命令操作,再到gtk的图形函数,最后到文件系统的详细解析。这些都能在网上找到。也因为这样,整个课程设计下来,我浏览的相关网页已经超过了100个(不完全统计)。当然网上的东西很乱很杂,自己要能够学会筛选。 不能决定对或错的,有个很简单的方法就是去尝试。就拿第二个实验来说,编译内核有很多项小操作,这些小操作错了一项就可能会导致编译的失败,而这又是非常要花时间的,我用的虚拟机,编译一次接近3小时。所以要非常的谨慎,尽量少出差错,节省时间。多找个几个参照资料,相互比较,

慢慢研究,最后才能事半功倍。 2、同学间的讨论,这是很重要的。老师毕竟比较忙。对于课程设计最大的讨论伴侣应该是同学了。能和学长学姐讨论当然再好不过了,没有这个机会的话,和自己班上同学讨论也是能够受益匪浅的。大家都在研究同样的问题,讨论起来,更能够把思路理清楚,相互帮助,可以大大提高效率。 3、敢于攻坚,越是难的问题,越是要有挑战的心理。这样就能够达到废寝忘食的境界。当然这也是不提倡熬夜的,毕竟有了精力才能够打持久战。但是做课设一定要有状态,能够在吃饭,睡觉,上厕所都想着要解决的问题,这样你不成功都难。 4、最好在做课设的过程中能够有记录的习惯,这样在写实验报告时能够比较完整的回忆起中间遇到的各种问题。比如当时我遇到我以前从未遇到的段错误的问题,让我都不知道从何下手。在经过大量的资料查阅之后,我对段错误有了一定的了解,并且能够用相应的办法来解决。 在编程中以下几类做法容易导致段错误,基本是是错误地使用指针引起的 1)访问系统数据区,尤其是往系统保护的内存地址写数据,最常见就是给一个指针以0地址 2)内存越界(数组越界,变量类型不一致等) 访问到不属于你的内存区域

操作系统实验报告-中南大学

操作系统原理试验报告 班级: 学号: 姓名:

实验一:CPU调度 一、实验内容 选择一个调度算法,实现处理机调度。 二、实验目的 多道系统中,当就绪进程数大于处理机数时,须按照某种策略决定哪些进程优先占用处理机。本实验模拟实现处理机调度,以加深了解处理机调度的工作。 三、实验题目 1、设计一个按优先权调度算法实现处理机调度的程序; 2、设计按时间片轮转实现处理机调度的程序。 四、实验要求 PCB内容: 进程名/PID; 要求运行时间(单位时间); 优先权; 状态: PCB指针; 1、可随机输入若干进程,并按优先权排序; 2、从就绪队首选进程运行:优先权-1/要求运行时间-1 要求运行时间=0时,撤销该进程 3、重新排序,进行下轮调度 4、最好采用图形界面; 5、可随时增加进程; 6、规定道数,设置后备队列和挂起状态。若内存中进程少于规定道数,可自动从后备 队列调度一作业进入。被挂起进程入挂起队列,设置解挂功能用于将指定挂起进程解挂入就绪队列。 7、每次调度后,显示各进程状态。 实验二:内存管理 一、实验内容 主存储器空间的分配和回收 二、实验目的 帮助了解在不同的存储管理方式下,应怎样实现主存空间的分配和回收。 三、实验题目 在可变分区管理方式下,采用最先适应算法实现主存空间的分配和回收。

四、实验要求 1、自行假设主存空间大小,预设操作系统所占大小并构造未分分区表; 表目内容:起址、长度、状态(未分/空表目) 2、结合实验一,PCB增加为: {PID,要求运行时间,优先权,状态,所需主存大小,主存起始位置,PCB指针} 3、采用最先适应算法分配主存空间; 4、进程完成后,回收主存,并与相邻空闲分区合并 .1、Vo类说明(数据存储结构) 进程控制块PCB的结构: Public class PCB{ //进程控制块PCB,代表一个进程 //进程名,作为进程的标识; private String name; //要求运行时间,假设进程运行的单位时间数; private int time; //赋予进程的优先权,调度时总是选取优先数小的进程先执行; private int priority; //状态,假设有“就绪”状态(ready)、“运行”状态(running)、 //“后备”状态(waiting)、“挂起”状态(handup) private String state; //进程存放在table中的位置 private int start; //进程的大小 private int length; //进程是否进入内存,1为进入,0为未进入 private int isIn; //进程在内存中的起始位置 private int base; //进程的大小 private int limit; //一些get和set方法以及构造器省略… };

操作系统实验报告

操作系统实验报告 实验名称: 系统的引导 所在班级: 指导老师: 老师 实验日期: 2014年3 月29 日

一、实验目的 ◆熟悉hit-oslab实验环境; ◆建立对操作系统引导过程的深入认识; ◆掌握操作系统的基本开发过程; ◆能对操作系统代码进行简单的控制,揭开操作系统的神秘面纱。 二、实验容 1. 阅读《Linux核完全注释》的第6章引导启动程序,对计算机和Linux 0.11的引导过程进行初步的了解。 2. 按照下面的要求改写0.11的引导程序bootsect.s。 3. 有兴趣同学可以做做进入保护模式前的设置程序setup.s。 4. 修改build.c,以便可以使用make BootImage命令 5. 改写bootsect.s主要完成如下功能: bootsect.s能在屏幕上打印一段提示信息XXX is booting...,其中XXX是你给自己的操作系统起的名字,例如LZJos、Sunix等。 6. 改写setup.s主要完成如下功能: bootsect.s能完成setup.s的载入,并跳转到setup.s开始地址执行。而setup.s 向屏幕输出一行"Now we are in SETUP"。setup.s能获取至少一个基本的硬件参数(如存参数、显卡参数、硬盘参数等),将其存放在存的特定地址,并输出到屏幕上。setup.s不再加载Linux核,保持上述信息显示在屏幕上即可。 三、实验环境

本实验使用的系统是windows系统或者是Linux系统,需要的材料是osexp。 四、实验步骤 1. 修改bootsect.s中的提示信息及相关代码; 到osexp\Linux-0.11\boot目录下会看到图1所示的三个文件夹,使用UtraEdit 打开该文件。将文档中的98行的mov cx,#24修改为mov cx,#80。同时修改文档中的第246行为图2所示的情形。 图1图2 图3 2. 在目录linux-0.11\boot下,分别用命令as86 -0 -a -o bootsect.obootsect.s和 ld86 -0 -s -obootsectbootsect.o编译和bootsect.s,生成bootsect文件; 在\osexp目录下点击MinGW32.bat依此输入下面的命令: cd linux-0.11 cd boot as86 -0 -a -o bootsect.obootsect.s ld86 -0 -s -o bootsectbootsect.o

嵌入式实时操作系统实验报告

嵌入式实时操作系统实验报告 任务间通信机制的建立 系别计算机与电子系 专业班级***** 学生姓名****** 指导教师 ****** 提交日期 2012 年 4 月 1 日

一、实验目的 掌握在基于嵌入式实时操作系统μC/OS-II的应用中,任务使用信号量的一般原理。掌握在基于优先级的可抢占嵌入式实时操作系统的应用中,出现优先级反转现象的原理及解决优先级反转的策略——优先级继承的原理。 二、实验内容 1.建立并熟悉Borland C 编译及调试环境。 2.使用课本配套光盘中第五章的例程运行(例5-4,例5-5,例5-6),观察运行结果,掌握信号量的基本原理及使用方法,理解出现优先级反转现象的根本原因并提出解决方案。 3.试编写一个应用程序,采用计数器型信号量(初值为2),有3个用户任务需要此信号量,它们轮流使用此信号量,在同一时刻只有两个任务能使用信号量,当其中一个任务获得信号量时向屏幕打印“TASK N get the signal”。观察程序运行结果并记录。 4. 试编写一个应用程序实现例5-7的内容,即用优先级继承的方法解决优先级反转的问题,观察程序运行结果并记录。 5.在例5-8基础上修改程序增加一个任务HerTask,它和YouTask一样从邮箱Str_Box里取消息并打印出来,打印信息中增加任务标识,即由哪个任务打印的;MyTask发送消息改为当Times为5的倍数时才发送,HerTask接收消息采用无等待方式,如果邮箱为空,则输出“The mailbox is empty”, 观察程序运行结果并记录。 三、实验原理 1. 信号量 μC/OS-II中的信号量由两部分组成:一个是信号量的计数值,它是一个16位的无符号整数(0 到65,535之间);另一个是由等待该信号量的任务组成的等待任务表。用户要在OS_CFG.H中将OS_SEM_EN开关量常数置成1,这样μC/OS-II 才能支持信号量。

操作系统实验报告

操作系统教程实验报告 专业班级 学号 姓名 指导教师

实验一WINDOWS进程初识 1、实验目的 (1)学会使用VC编写基本的Win32 Consol Application(控制台应用程序)。 (2)掌握WINDOWS API的使用方法。 (3)编写测试程序,理解用户态运行和核心态运行。 2、实验内容和步骤 (1)编写基本的Win32 Consol Application 步骤1:登录进入Windows,启动VC++ 6.0。 步骤2:在“FILE”菜单中单击“NEW”子菜单,在“projects”选项卡中选择“Win32 Consol Application”,然后在“Project name”处输入工程名,在“Location”处输入工程目录。创建一个新的控制台应用程序工程。 步骤3:在“FILE”菜单中单击“NEW”子菜单,在“Files”选项卡中选择“C++ Source File”, 然后在“File”处输入C/C++源程序的文件名。 步骤4:将清单1-1所示的程序清单复制到新创建的C/C++源程序中。编译成可执行文件。 步骤5:在“开始”菜单中单击“程序”-“附件”-“命令提示符”命令,进入Windows “命令提示符”窗口,然后进入工程目录中的debug子目录,执行编译好的可执行程序:E:\课程\os课\os实验\程序\os11\debug>hello.exe 运行结果 (如果运行不成功,则可能的原因是什么?) : (2)计算进程在核心态运行和用户态运行的时间 步骤1:按照(1)中的步骤创建一个新的“Win32 Consol Application”工程,然后将清单1-2中的程序拷贝过来,编译成可执行文件。 步骤2:在创建一个新的“Win32 Consol Application”工程,程序的参考程序如清单1-3所示,编译成可执行文件并执行。 步骤3:在“命令提示符”窗口中运行步骤1中生成的可执行文件,测试步骤2中可执行文件在核心态运行和用户态运行的时间。 E:\课程\os课\os实验\程序\os12\debug>time TEST.exe 步骤4:运行结果 (如果运行不成功,则可能的原因是什么?) : 步骤5:分别屏蔽While循环中的两个for循环,或调整两个for循环的次数,写出运行结果。 屏蔽i循环:

操作系统实验报告

《操作系统原理》实验报告 实验项目名称:模拟使用银行家算法判断系统的状态 一、实验目的 银行家算法是操作系统中避免死锁的算法,本实验通过对银行家算法的模拟,加强对操作系统中死锁的认识,以及如何寻找到一个安全序列解除死锁。 二、实验环境 1、硬件:笔记本。 2、软件:Windows 7 , Eclipse。 三、实验内容 1.把输入资源初始化,形成资源分配表; 2.设计银行家算法,输入一个进程的资源请求,按银行家算法步骤进行检查; 3.设计安全性算法,检查某时刻系统是否安全; 4.设计显示函数,显示资源分配表,安全分配序列。 四、数据处理与实验结果 1.资源分配表由进程数组,Max,Allocation,Need,Available 5个数组组成; 实验采用数据为下表: 2.系统总体结构,即菜单选项,如下图

实验的流程图。如下图 3.实验过程及结果如下图所示

1.首先输入进程数和资源类型及各进程的最大需求量 2.输入各进程的占有量及目前系统的可用资源数量 3.初始化后,系统资源的需求和分配表 4.判断线程是否安全

5.对线程进行死锁判断 五、实验过程分析 在实验过程中,遇到了不少问题,比如算法无法回滚操作,程序一旦执行,必须直接运行到单个任务结束为止,即使产生了错误,也必须等到该项任务结束才可以去选择别的操作。但总之,实验还是完满的完成了。 六、实验总结 通过实验使我对以前所学过的基础知识加以巩固,也对操作系统中抽象理论知识加以理解,例如使用Java语言来实现银行家算法,在这个过程中更进一步了解了银行家算法,通过清晰字符界面能进行操作。不过不足之处就是界面略显简洁,对于一个没有操作过计算机的人来说,用起来可能还是有些难懂。所以,以后会对界面以及功能进行完善,做到人人都可以看懂的算法。

操作系统实验报告

操作系统实验报告 Document number:NOCG-YUNOO-BUYTT-UU986-1986UT

许昌学院 《操作系统》实验报告书学号: 姓名:闫金科 班级:14物联网工程 成绩: 2016年02月

实验一Linux的安装与配置 一、实验目的 1.熟悉Linux系统的基本概念,比如Linux发行版、宏内核、微内核等。 2.掌握Linux系统的安装和配置过程,初步掌握Linux系统的启动和退出方 法。 3.熟悉Linux系统的文件系统结构,了解Linux常用文件夹的作用。 二、实验内容 1.从网络上下载VMware软件和两个不同Linux发行版镜像文件。 2.安装VMware虚拟机软件。 3.在VMware中利用第一个镜像文件完成第一个Linux的安装,期间完成网络 信息、用户信息、文件系统和硬盘分区等配置。 4.在VMware中利用第二个镜像文件完成第二个Linux的安装,并通过LILO或 者GRUB解决两个操作系统选择启动的问题。 5.启动Linux系统,打开文件浏览器查看Linux系统的文件结构,并列举出 Linux常用目录的作用。 三、实验过程及结果 1、启动VMware,点击新建Linux虚拟机,如图所示: 2、点击下一步,选择经典型,点击下一步在选择客户机页面选择 Linux,版本选择RedHatEnterpriseLinux5,如图所示: 3、点击下一步创建虚拟机名称以及所要安装的位置,如图所示: 4、点击下一步,磁盘容量填一个合适大小,此处选择默认值大小 10GB,如图所示: 5、点击完成,点击编辑虚拟机设置,选择硬件选项中的CD-ROM (IDE...)选项,在右侧连接中选择“使用ISO镜像(I)”选项,点 击“浏览”,找到Linux的镜像文件,如图所示:

操作系统实验报告

实验报告 实验课程名称:操作系统 实验地点:南主楼七楼机房 2018—2019学年(一)学期 2018年 9月至 2019 年 1 月 专业: 班级: 学号: 姓名: 指导老师:刘一男

实验一 实验项目:分时系统模拟 实验学时:2实验日期: 2018-10-25 成绩: 实验目的利用程序设计语言模拟分时系统中多个进程按时间片轮转调度算法进行进程调度的过程; 假设有五个进程A,B,C,D,E,它们的到达时间及要求服务的时间分别为:进程名 A B C D E 到达时间0 1 2 3 4 服务时间 4 3 4 2 4 时间片大小为1,利用程序模拟A,B,C,D,E五个进程按时间片轮转的调度及执行过程并计算各进程的周转时间及带权周转时间。 执行过程并计算各进程的周转时间及带权周转时间。 轮转调度:BDACE

(1)修改时间片大小为2,利用程序模拟A,B,C,D,E五个进程按时间片轮转的调度及执行过程并计算各进程的周转时间及带权周转时间。 轮转调度:ADBCE (2)修改时间片大小为4,利用程序模拟A,B,C,D,E五个进程按时间片轮转的调度及执行过程并计算各进程的周转时间及带权周转时间.

顺序:ABCDE 1、思考 时间片的大小对调度算法产生什么影响?对计算机的性能产生什么影响?答:通过对时间片轮转调度算法中进程最后一次执行时间片分配的优化,提出了一种改进的时间片轮转调度算法,该算法具有更好的实时性,同时减少了任务调度次数和进程切换次数,降低了系统开销,提升了CPU的运行效率,使操作系统的性能得到了一定的提高。 A B C D E 时间片为1 周转时间12 9 14 8 13 3 3 3.5 4 3.25 带权周转 时间 时间片为2 周转时间8 12 13 7 13 2 4 3.25 3.5 3.25 带权周转 时间 时间片为4 周转时间 4 6 9 10 13 1 2 2.25 5 3.25 带权周转 时间

操作系统实验一实验报告

操作系统实验一实验报告 基本信息 1.1 实验题目 进程控制实验 1.2完成人 王召德 1.3报告日期 2015-4-8 实验内容简要描述 2.1实验目标 加深对于进程并发执行概念的理解。实践并发进程的创建和控制方法。观察和 体验进程的动态特性。进一步理解进程生命期期间创建、变换、撤销状态变换的过 程。掌握进程控制的方法,了解父子进程间的控制和协作关系。练习Linux 系统中 进程创建与控制有关的系统调用的编程和调试技术。 2.2实验要求 参考以上示例程序中建立并发进程的方法,编写一个多进程并发执行程序。父进程首先创建一个执行ls命令的子进程然后再创建一个执行ps命令的子进程,并控制ps 命令总在ls 命令之前执行。 2.3实验的软硬件环境

Ubuntu14.04 intelPC 报告的主要内容 3.1实验的思路 按照上面的实例,先生成一个子进程让其等待,然后生成第二个子进程,父进程等待其执行ps命令后唤醒第一个子进程执行ls即可。 3.2实验模型的描述 无 3.3主要数据结构的分析说明 无 3.4主要算法代码的分析说明 无 3.5项目管理文件的说明 无 实验过程和结果 4.1实验投入的实际学时数 1学时 4.2调试排错过程的记录 曾尝试让第二个子进程激活第一个子进程,结果发现当运行ps后,后面的代码将不再执行,所以不可行。 4.3多种方式测试结果的记录

实验结果: 父进程启动 (12239) ls子进程启动 (12240) ps子进程启动 (12241) PID TTY TIME CMD 12239 pts/27 00:00:00 born 12240 pts/27 00:00:00 born 12241 pts/27 00:00:00 ps ps子进程结束 (12241) 唤醒ls子进程 (12240) 键盘中断信号产生... ls子进程被唤醒 (12240) . born born.c~ hello.c pctl pctl.c~ pctl.o .. born.c helelo.h~ hello.c~ pctl.c pctl.h ls子进程结束 (12240) 父进程结束 (12239) 4.4实验结果的分析综合 无 实验的总结 父进程可以通过fork()函数生成子进程,子进程会从fork()函数开始执行原来的代码,当

相关主题
文本预览
相关文档 最新文档