梁广轩_1505010601_实验4
来源:互联网 发布:那年夏天宁静的海 知乎 编辑:程序博客网 时间:2024/06/06 14:22
Linux 系统分析实验报告 实验4
提交日期:2017.04.28
提交截止日期:2017.04.28
姓名:梁广轩
学号:1505010601
班级:计算机科学与技术6班
一、 实验题目
1.Windows 进程管理。
2.Linux 进程管理。
3.进程同步的经典算法。
二、 实验目的
1.Windows 进程管理:
(1)学会使用 VC 编写基本的 Win32 Consol Application(控制台应用程序)。
(2)通过创建进程、观察正在运行的进程和终止进程的程序设计和调试操作,进一步熟悉操 作系统的进程概念,理解 Windows 进程的“一生”。
(3)通过阅读和分析实验程序,学习创建进程、观察进程、终止进程以及父子进程同步的基 本程序设计方法。
2.Linux 进程管理:
通过进程的创建、撤销和运行加深对进程概念和进程并发执行的理解,明确进程和程序之间的 区别。
3.进程同步的经典算法:
(1) 回顾系统进程、线程的有关概念,加深对 Windows 线程的理解。
(2) 了解互斥体对象,通过对生产者消费者等进程间同步与互斥经典算法的实现,加深对 P (即 semWait)、V(即 semSignal)原语以及利用 P、V 原语进行进程间同步与互斥操作的理解。
三、 实验平台
windows系统和装有LinuxMint的Linux虚拟机。
四、 实验要求
1.Windows 进程管理:
(1)编写基本的 Win32 Consol Application。
(2) 创建进程。
(3) 父子进程的简单通信及终止进程。
2.Linux 进程管理:
(1)进程的创建。
(2)子进程执行新任务。
3.进程同步的经典算法:
(1) 生产者消费者问题。
4.独立完成。
五、设计思路和流程图
1.设计思路
在windows系统和Linux虚拟机上编写程序。
2.实验流程
在windows系统的”VC++6.0“中创建“Win32 Consol Application”应用程序工程。
创建“1-1代码.cpp”文件并打开。
// hello 项目# include <iostream>int main(){ std::cout << "Hello, Win32 Consol Application" << std :: endl ;}
编译”1-1代码.cpp“并用cmd运行。
运行结果:
任务1-1完成。
在windows系统的”VC++6.0“中创建“Win32 Consol Application”应用程序工程。
创建“1-2代码.cpp”文件并打开。
#include <windows.h>#include <iostream>#include <stdio.h>// 创建传递过来的进程的克隆过程并赋于其 ID 值void StartClone(int nCloneID){ // 提取用于当前可执行文件的文件名 TCHAR szFilename[MAX_PATH] ; GetModuleFileName(NULL, szFilename, MAX_PATH) ; // 格式化用于子进程的命令行并通知其 EXE 文件名和克隆 ID TCHAR szCmdLine[MAX_PATH]; sprintf(szCmdLine,"\"%s\" %d",szFilename,nCloneID); // 用于子进程的 STARTUPINFO 结构 STARTUPINFO si; ZeroMemory(&si , sizeof(si) ) ; si.cb = sizeof(si) ; // 必须是本结构的大小 // 返回的用于子进程的进程信息 PROCESS_INFORMATION pi; // 利用同样的可执行文件和命令行创建进程,并赋于其子进程的性质 BOOL bCreateOK=::CreateProcess( szFilename, // 产生这个 EXE 的应用程序的名称 szCmdLine, // 告诉其行为像一个子进程的标志 NULL, // 缺省的进程安全性 NULL, // 缺省的线程安全性 FALSE, // 不继承句柄 CREATE_NEW_CONSOLE, // 使用新的控制台 NULL, // 新的环境 NULL, // 当前目录 &si, // 启动信息 &pi) ; // 返回的进程信息 // 对子进程释放引用 if (bCreateOK) { CloseHandle(pi.hProcess) ; CloseHandle(pi.hThread) ; }}int main(int argc, char* argv[] ){ // 确定派生出几个进程,及派生进程在进程列表中的位置 int nClone=0; //修改语句:int nClone;//第一次修改:nClone=0; if (argc > 1) { // 从第二个参数中提取克隆 ID :: sscanf(argv[1] , "%d" , &nClone) ; }//第二次修改:nClone=0; // 显示进程位置 std :: cout << "Process ID:" << :: GetCurrentProcessId() << ", Clone ID:" << nClone << std :: endl; // 检查是否有创建子进程的需要 const int c_nCloneMax=5; if (nClone < c_nCloneMax) { // 发送新进程的命令行和克隆号 StartClone(++nClone) ; } // 等待响应键盘输入结束进程 getchar(); return 0; }
编译”1-2代码.cpp“并用cmd运行。
运行结果:
进程:
打开”1-2代码.cpp“文件并修改代码为:
#include <windows.h>#include <iostream>#include <stdio.h>// 创建传递过来的进程的克隆过程并赋于其 ID 值void StartClone(int nCloneID){ // 提取用于当前可执行文件的文件名 TCHAR szFilename[MAX_PATH] ; GetModuleFileName(NULL, szFilename, MAX_PATH) ; // 格式化用于子进程的命令行并通知其 EXE 文件名和克隆 ID TCHAR szCmdLine[MAX_PATH]; sprintf(szCmdLine,"\"%s\" %d",szFilename,nCloneID); // 用于子进程的 STARTUPINFO 结构 STARTUPINFO si; ZeroMemory(&si , sizeof(si) ) ; si.cb = sizeof(si) ; // 必须是本结构的大小 // 返回的用于子进程的进程信息 PROCESS_INFORMATION pi; // 利用同样的可执行文件和命令行创建进程,并赋于其子进程的性质 BOOL bCreateOK=::CreateProcess( szFilename, // 产生这个 EXE 的应用程序的名称 szCmdLine, // 告诉其行为像一个子进程的标志 NULL, // 缺省的进程安全性 NULL, // 缺省的线程安全性 FALSE, // 不继承句柄 CREATE_NEW_CONSOLE, // 使用新的控制台 NULL, // 新的环境 NULL, // 当前目录 &si, // 启动信息 &pi) ; // 返回的进程信息 // 对子进程释放引用 if (bCreateOK) { CloseHandle(pi.hProcess) ; CloseHandle(pi.hThread) ; }}int main(int argc, char* argv[] ){ // 确定派生出几个进程,及派生进程在进程列表中的位置 int nClone=0; //修改语句:int nClone;//第一次修改:nClone=0; if (argc > 1) { // 从第二个参数中提取克隆 ID :: sscanf(argv[1] , "%d" , &nClone) ; }nClone=0; // 显示进程位置 std :: cout << "Process ID:" << :: GetCurrentProcessId() << ", Clone ID:" << nClone << std :: endl; // 检查是否有创建子进程的需要 const int c_nCloneMax=5; if (nClone < c_nCloneMax) { // 发送新进程的命令行和克隆号 StartClone(++nClone) ; } // 等待响应键盘输入结束进程 getchar(); return 0; }
编译”1-2代码.cpp“并用cmd运行。
运行结果:
(不停地创建子进程。)
进程:
(创建出了很多的子进程。)
任务1-2完成。
在windows系统的”VC++6.0“中创建“Win32 Consol Application”应用程序工程。
创建“1-3代码.cpp”文件并打开。
// procterm 项目 # include <windows.h> # include <iostream> # include <stdio.h> static LPCTSTR g_szMutexName = "w2kdg.ProcTerm.mutex.Suicide" ; // 创建当前进程的克隆进程的简单方法 void StartClone() { // 提取当前可执行文件的文件名 TCHAR szFilename[MAX_PATH] ; GetModuleFileName(NULL, szFilename, MAX_PATH) ; // 格式化用于子进程的命令行,字符串“child”将作为形参传递给子进程的 main 函数 TCHAR szCmdLine[MAX_PATH] ; //实验 1-3 步骤 3:将下句中的字符串 child 改为别的字符串,重新编译执行,执行前请先保存已经 完成的工作 sprintf(szCmdLine, "\"%s\"child" , szFilename) ; // 子进程的启动信息结构 STARTUPINFO si; ZeroMemory(&si,sizeof(si)) ; si.cb = sizeof(si) ; // 应当是此结构的大小 // 返回的用于子进程的进程信息 PROCESS_INFORMATION pi; // 用同样的可执行文件名和命令行创建进程,并指明它是一个子进程 BOOL bCreateOK=CreateProcess( szFilename, // 产生的应用程序的名称 (本 EXE 文件) szCmdLine, // 告诉我们这是一个子进程的标志 NULL, // 用于进程的缺省的安全性 NULL, // 用于线程的缺省安全性 FALSE, // 不继承句柄 CREATE_NEW_CONSOLE, //创建新窗口 NULL, // 新环境 NULL, // 当前目录 &si, // 启动信息结构 &pi ) ; // 返回的进程信息 // 释放指向子进程的引用 if (bCreateOK) { CloseHandle(pi.hProcess) ; CloseHandle(pi.hThread) ; } } void Parent() { // 创建“自杀”互斥程序体 HANDLE hMutexSuicide=CreateMutex( 7 NULL, // 缺省的安全性 TRUE, // 初拥有的 g_szMutexName) ; // 互斥体名称 if (hMutexSuicide != NULL) { // 创建子进程 std :: cout << "Creating the child process." << std :: endl; StartClone() ; // 指令子进程“杀”掉自身 std :: cout << "Telling the child process to quit. "<< std :: endl; //等待父进程的键盘响应 getchar() ; //释放互斥体的所有权,这个信号会发送给子进程的 WaitForSingleObject 过程 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) ; //实验 1-3 步骤 4:将上句改为 WaitForSingleObject(hMutexSuicide, 0) ,重新编译执行 // 准备好终止,清除句柄 std :: cout << "Child quiting." << std :: endl; CloseHandle(hMutexSuicide) ; } } int main(int argc, char* argv[] ) { // 决定其行为是父进程还是子进程 if (argc>1 && :: strcmp(argv[1] , "child" )== 0) { Child() ; } else { Parent() ; } return 0; }
编译”1-3代码.cpp“并用cmd运行。
运行结果:
打开”1-3代码.cpp“文件将代码修改为:
// procterm 项目 # include <windows.h> # include <iostream> # include <stdio.h> static LPCTSTR g_szMutexName = "w2kdg.ProcTerm.mutex.Suicide" ; // 创建当前进程的克隆进程的简单方法 void StartClone() { // 提取当前可执行文件的文件名 TCHAR szFilename[MAX_PATH] ; GetModuleFileName(NULL, szFilename, MAX_PATH) ; // 格式化用于子进程的命令行,字符串“child”将作为形参传递给子进程的 main 函数 TCHAR szCmdLine[MAX_PATH] ; //实验 1-3 步骤 3:将下句中的字符串 child 改为别的字符串,重新编译执行,执行前请先保存已经 完成的工作 sprintf(szCmdLine, "\"%s\"child" , szFilename) ; // 子进程的启动信息结构 STARTUPINFO si; ZeroMemory(&si,sizeof(si)) ; si.cb = sizeof(si) ; // 应当是此结构的大小 // 返回的用于子进程的进程信息 PROCESS_INFORMATION pi; // 用同样的可执行文件名和命令行创建进程,并指明它是一个子进程 BOOL bCreateOK=CreateProcess( szFilename, // 产生的应用程序的名称 (本 EXE 文件) szCmdLine, // 告诉我们这是一个子进程的标志 NULL, // 用于进程的缺省的安全性 NULL, // 用于线程的缺省安全性 FALSE, // 不继承句柄 CREATE_NEW_CONSOLE, //创建新窗口 NULL, // 新环境 NULL, // 当前目录 &si, // 启动信息结构 &pi ) ; // 返回的进程信息 // 释放指向子进程的引用 if (bCreateOK) { CloseHandle(pi.hProcess) ; CloseHandle(pi.hThread) ; } } void Parent() { // 创建“自杀”互斥程序体 HANDLE hMutexSuicide=CreateMutex( 7 NULL, // 缺省的安全性 TRUE, // 初拥有的 g_szMutexName) ; // 互斥体名称 if (hMutexSuicide != NULL) { // 创建子进程 std :: cout << "Creating the child process." << std :: endl; StartClone() ; // 指令子进程“杀”掉自身 std :: cout << "Telling the child process to quit. "<< std :: endl; //等待父进程的键盘响应 getchar() ; //释放互斥体的所有权,这个信号会发送给子进程的 WaitForSingleObject 过程 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) ; WaitForSingleObject(hMutexSuicide, 0) ,重新编译执行 // 准备好终止,清除句柄 std :: cout << "Child quiting." << std :: endl; CloseHandle(hMutexSuicide) ; } } int main(int argc, char* argv[] ) { // 决定其行为是父进程还是子进程 if (argc>1 && :: strcmp(argv[1] , "child" )== 0) { Child() ; } else { Parent() ; } return 0; }
编译”1-3代码.cpp“并用cmd运行。
运行结果:
任务1-3完成。
在linux系统的命令行中输入vim fork_demo.c创建文件并打开。
在命令行输入gcc –o fork_demo fork_demo.c 完成编译。
在命令行输入./fork_demo 运行程序20次。
运行结果:
任务2-1完成。
在linux系统的命令行中输入 exec_demo.c创建文件并打开。
在命令行输入gcc –o exec_demo exec_demo.c 完成编译。
在命令行输入入./exec_demo 运行程序。
运行结果:
任务2-2完成。
在windows系统的”VC++6.0“中创建“Win32 Consol Application”应用程序工程。
创建“3-1代码.cpp”文件并打开。
#include <windows.h> #include <iostream> const unsigned short SIZE_OF_BUFFER = 2; //缓冲区长度 unsigned short ProductID = 0; //产品号 unsigned short ConsumeID = 0; //将被消耗的产品号 unsigned short in = 0; //产品进缓冲区时的缓冲区下标 unsigned short out = 0; //产品出缓冲区时的缓冲区下标 int buffer[SIZE_OF_BUFFER]; //缓冲区是个循环队列 12 bool p_ccontinue = true; //控制程序结束 HANDLE Mutex; //用于线程间的互斥 HANDLE FullSemaphore; //当缓冲区满时迫使生产者等待 HANDLE EmptySemaphore; //当缓冲区空时迫使消费者等待 DWORD WINAPI Producer(LPVOID); //生产者线程 DWORD WINAPI Consumer(LPVOID); //消费者线程 int main() { //创建各个互斥信号 //注意,互斥信号量和同步信号量的定义方法不同,互斥信号量调用的是 CreateMutex 函数, 同步信号量 //调用的是 CreateSemaphore 函数,函数的返回值都是句柄。 Mutex = CreateMutex(NULL,FALSE,NULL); EmptySemaphore = CreateSemaphore(NULL,SIZE_OF_BUFFER,SIZE_OF_BUFFER,NULL); //将上句做如下修改,看看结果会怎样 //EmptySemaphore = CreateSemaphore(NULL,0,SIZE_OF_BUFFER-1,NULL); FullSemaphore = CreateSemaphore(NULL,0,SIZE_OF_BUFFER,NULL); //调整下面的数值,可以发现,当生产者个数多于消费者个数时, //生产速度快,生产者经常等待消费者;反之,消费者经常等待 const unsigned short PRODUCERS_COUNT = 3; //生产者的个数 const unsigned short CONSUMERS_COUNT = 1; //消费者的个数 //总的线程数 const unsigned short THREADS_COUNT = PRODUCERS_COUNT+CONSUMERS_COUNT; HANDLE hThreads[THREADS_COUNT]; //各线程的 handle DWORD producerID[PRODUCERS_COUNT]; //生产者线程的标识符 DWORD consumerID[CONSUMERS_COUNT]; //消费者线程的标识符 //创建生产者线程 for (int i=0;i<PRODUCERS_COUNT;++i){ hThreads[i]=CreateThread(NULL,0,Producer,NULL,0,&producerID[i]); if (hThreads[i]==NULL) return -1; } //创建消费者线程 for (i=0;i<CONSUMERS_COUNT;++i){ hThreads[PRODUCERS_COUNT+i]=CreateThread(NULL,0,Consumer,NULL,0,&consumerID[i]); if (hThreads[i]==NULL) return -1; } while(p_ccontinue){ if(getchar()){ //按回车后终止程序运行 13 p_ccontinue = false; } } return 0; } //生产一个产品。简单模拟了一下,仅输出新产品的 ID 号 void Produce() { std::cout << std::endl<< "Producing " << ++ProductID << " ... "; std::cout << "Succeed" << std::endl; } //把新生产的产品放入缓冲区 void Append() { std::cerr << "Appending a product ... "; buffer[in] = ProductID; in = (in+1)%SIZE_OF_BUFFER; std::cerr << "Succeed" << std::endl; //输出缓冲区当前的状态 for (int i=0;i<SIZE_OF_BUFFER;++i){ std::cout << i <<": " << buffer[i]; if (i==in) std::cout << " <-- 生产"; if (i==out) std::cout << " <-- 消费"; std::cout << std::endl; } } //从缓冲区中取出一个产品 void Take() { std::cerr << "Taking a product ... "; ConsumeID = buffer[out]; buffer[out] = 0; out = (out+1)%SIZE_OF_BUFFER; std::cerr << "Succeed" << std::endl; //输出缓冲区当前的状态 for (int i=0;i<SIZE_OF_BUFFER;++i){ std::cout << i <<": " << buffer[i]; if (i==in) std::cout << " <-- 生产"; if (i==out) std::cout << " <-- 消费"; std::cout << std::endl; } 14 } //消耗一个产品 void Consume() { std::cout << "Consuming " << ConsumeID << " ... "; std::cout << "Succeed" << std::endl; } //生产者 DWORD WINAPI Producer(LPVOID lpPara) { while(p_ccontinue){ WaitForSingleObject(EmptySemaphore,INFINITE); //p(empty); WaitForSingleObject(Mutex,INFINITE); //p(mutex); Produce(); Append(); Sleep(1500); ReleaseMutex(Mutex); //V(mutex); ReleaseSemaphore(FullSemaphore,1,NULL); //V(full); } return 0; } //消费者 DWORD WINAPI Consumer(LPVOID lpPara) { while(p_ccontinue){ WaitForSingleObject(FullSemaphore,INFINITE); //P(full); WaitForSingleObject(Mutex,INFINITE); //P(mutex); Take(); Consume(); Sleep(1500); ReleaseMutex(Mutex); //V(mutex); ReleaseSemaphore(EmptySemaphore,1,NULL); //V(empty); } return 0; }
编译”3-1代码.cpp“并用cmd运行。
运行结果:
任务3-1完成。
六、实验体会
通过不停地查找资料,我终于完成了编写和修改程序的任务,对windows和linux系统中进程和进程同步的使用了更深一步的了解。
七、程序清单
1.windows系统下的“Oracle VM VirtualBox管理器“和”VC++6.0“。
2.linux系统下的vim、gcc工具。
0 0
- 梁广轩_1505010601_实验4
- 梁广轩_1505010601_实验1
- 梁广轩_1505010601_实验2
- 梁广轩_1505010601_实验3
- 实验4
- 实验4
- 实验4
- 实验4
- 实验4
- 实验-4
- 实验4
- 实验4
- 实验4
- 第四章实验3.实验4
- 实验:C++实验4-项目6
- 实验:c++实验4-项目6
- 实验:C++实验4-项目6
- 实验:C++实验4-百钱百鸡问题
- Flask应用部署
- 即拿即用-仿IOS风格的弹出框和对话框
- 从零开始学dagger2
- 安全渗透测试网站
- Huffman 编码 实验报告
- 梁广轩_1505010601_实验4
- Java开发的准备
- 389. Find the Difference
- 正则匹配主机及端口
- 搬运自己的mysql学习笔记1.工具类的抽取
- Redis之链表
- AJAX开发基础及原生JS操作步骤
- 利用JFreeChart绘制股票K线图
- CodeForces 801B Valued Keys