梁广轩_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
原创粉丝点击