实 验 报 告
成绩 * 师: ** 2016 年 12月 17日
班 级: 1403018 学 号: ********* * 名: ** 实验地点: E-Ⅲ区208 实验时间: 2016.10.13—2016.12.17
实验一 创建进程
【实验软硬件环境】
VC 【实验内容】
实验内容:父进程创建一个有名事件, 由子进程发送事件信号,父进程获
取事 件信号后进行相应的处理
【实验原理】
父进程创建子进程,实现多个进程并发执行,提高计算机的运行效率。
【实验程序及分析】
试验程序源代码如下: 父进程部分代码:
// test1.cpp : Defines the entry point for the console application.
#include \"stdafx.h\" #include \"stdio.h\" #include \"stdlib.h\" #include \"windows.h\" int main(int argc, char* argv[]) {
STARTUPINFO sui;
ZeroMemory(&sui,sizeof(sui)); sui.cb=sizeof(STARTUPINFO); PROCESS_INFORMATION pi;
if(!CreateProcess(\"D:\\\\Test1\\\est1\\\est1zi.exe\TE_NE
W_CONSOLE,NULL,NULL,&sui,&pi)){
printf(\"子进程创建失败,即将退出程序!\\n\"); return 0;
} else{ }
Sleep(3000);
int sum = 0;
for(int i=1; i<=100; i++){ }
sum += i;
printf(\"sum = %d\\n\
WaitForSingleObject( pi.hProcess,INFINITE); }
子进程部分代码:
// test1zi.cpp : Defines the entry point for the console application. //
FILE *qp;
if((qp = fopen(\"D:\\\\Test1\\\\abc.txt\ } else{ } return 0;
char ch;
while((ch = fgetc(qp))!=EOF){ }
printf(\"\\n\"); fclose(qp);
printf(\"%c\
printf(\"读文件打开失败!\\n\"); return 0;
#include \"stdafx.h\" #include \"stdio.h\" #include \"stdlib.h\" #include \"windows.h\" int main(int argc, char* argv[]) {
FILE *qp;
if((qp = fopen(\"D:\\\\Test1\\\\abc.txt\ } else{
char ch;
while((ch = fgetc(qp))!=EOF){ }
printf(\"\\n\");
printf(\"%c\
printf(\"读文件打开失败!\\n\"); return 0;
printf(\"已经创建子进程\\n\"); FILE *fp;
if((fp = fopen(\"D:\\\\Test1\\\\abc.txt\ } else{ }
fprintf(fp,\"XiDian University\"); fclose(fp);
printf(\"数据已经写入成功\\n\"); printf(\"文件创建失败!\\n\"); return 0;
}
}
fclose(qp);
printf(\"数据读出成功\\n\");
Sleep(3000); return 0;
【实验结果截图】 父进程截图:
子进程截图:
【实验心得体会】
第一次操作系统上机,遇到了很多为问题。在学长和学姐的耐心指导下,解决了所有存在的问题,顺利完成了上机题目。通过这次上机,掌握了父进程创建子进程的方法,对操作系统多线程的认识进一步加深。
实验二 进程共享进程数据
【实验软硬件环境】
VC
【实验内容】
在进程中定义全局共享数据,在线程中直接引用该数据进行更改并输出该数据。
【实验原理】
定义一个全局变量,主进程可他创建的线程均可以实现对全局变量的访问和
修改。
【实验程序及分析】 //
#include \"stdafx.h\" #include DWORD WINAPI ThreadProc(LPVOID IpParameter){ for(count =1; count <=5; count++){ } printf(\"count = %d\\n\程序代码如下: // Test2.cpp : Defines the entry point for the console application. } return 0; int main(int argc, char* argv[]) { printf(\"线程运行!\\n\"); printf(\"count = %d\\n\printf(\"新线程运行\\n\"); HANDLE hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL); Sleep(5000); CloseHandle(hThread); printf(\"线程等待五秒钟!\\n\"); printf(\"新线程结束!\\n\"); printf(\"线程结束!\\n\"); return 0; } 【实验结果截图】 【实验心得体会】 这次实验内实现了主线程和他创建的线程对共享数据的读取和修改操作,定义的全局变 量是程序中的共享数据,线程对其均有访问和修改的权利。对线程间的共享数据有了初步认识。 实验三 信号通信 【实验软硬件环境】 VC++ 【实验内容】 父进程创建一个有名事件,由子进程发送事件信号,父进程获取事件信号后进行相应的处理。 【实验程序及分析】 父进程程序: // #include \"stdafx.h\" #include \"process.h\" #include \"windows.h\" int main(int argc, char* argv[]) { HANDLE hinstance = CreateEvent(NULL, FALSE,FALSE, \"NewEvnet\"); STARTUPINFO sui; ZeroMemory(&sui,sizeof(sui)); sui.cb=sizeof(STARTUPINFO); // Processs.cpp : Defines the entry point for the console application. PROCESS_INFORMATION pi; if(!CreateProcess(\"F:\\\\练习源代码\\\\c语言\\\\操作系统上机 \\\\Test3\\\\ChildProcess\\\\Debug\\\\ChildProcess.exe\CREATE_NEW_CONSOLE, NULL, NULL, &sui, &pi)) { } 子进程程序: // #include \"stdafx.h\" #include \"process.h\" #include \"windows.h\" int main(int argc, char* argv[]) { HANDLE hinstance = OpenEvent(EVENT_ALL_ACCESS, false, \"NewEvent\"); Sleep(3000); printf(\"Signal the event to Parent?[y\\\\n]\\n\"); char signal; // ChildProcess.cpp : Defines the entry point for the console application. if(WAIT_FAILED == WaitForSingleObject(hinstance, 10000)) { printf(\"wait failed\\n\"); printf(\"failed to create child process\\n\"); } else { } printf(\"Waiting for Event\\n\"); } else { } printf(\"Get the Event\\n\"); } scanf(\"%c\if(signal == 'y') SetEvent(hinstance); Sleep(3000); return 0; 【实验结果截图】 【实验心得体会】 父进程创建子进程创建了一个有名事件,并且用来接收子进程发送的信号。 通过这次实验对父子进程间的关系有了更多的认识,掌握了一些父子进程间的通 信方法。 实验四 匿名管道通信 【实验软硬件环境】 Vc++ 【实验内容】 分别建立名为 Parent 的单文档应用程序和 Child 的单文档应用程序作为父 子进程,由父 进程创建一个匿名管道,实现父子进程向匿名管道写入和读取数据。 【实验程序及分析】 第四题的Fraim文件下,摘取主要内容: 父进程的主要代码如下: void CParentView::OnPipeCreate() { STARTUPINFO sui; PROCESS_INFORMATION pi; if(!CreatePipe(&hRead,&hWrite,&sa,0)) { } AfxMessageBox(\"创建匿名管道失败!\"); return; SECURITY_ATTRIBUTES sa; sa.bInheritHandle=TRUE; //子进程可以继承父进程创建的匿名管道的读写句柄 sa.lpSecurityDescriptor=NULL; sa.nLength=sizeof(SECURITY_ATTRIBUTES); ZeroMemory(&sui,sizeof(STARTUPINFO)); sui.cb=sizeof(STARTUPINFO); sui.dwFlags=STARTF_USESTDHANDLES; //表示当前STARTUPINFO这个结构体变量中的标准输入、标准输出和标准错误句柄三 个成员是有用的 if(!CreateProcess(\"..\\\\Child\\\\Debug\\\\Child.exe\sui.hStdInput=hRead; //这里将子进程的标准输入和标准输出句柄分别设置为管道的读写句柄 sui.hStdOutput=hWrite; sui.hStdError=GetStdHandle(STD_ERROR_HANDLE); &sui,&pi)) } void CParentView::OnPipeRead() { char buf[100]={0}; { } else { } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); CloseHandle(hRead); CloseHandle(hWrite); hRead=NULL; hWrite=NULL; AfxMessageBox(\"创建子进程失败!\"); return; } DWORD dwRead; if(!ReadFile(hRead,buf,100,&dwRead,NULL)) { } AfxMessageBox(buf); AfxMessageBox(\"读取数据失败!\"); return; void CParentView::OnPipeWrite() { } 子进程的主要代码如下: char buf[]=\"父进程信息\"; DWORD dwWrite; if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL)) { } AfxMessageBox(\"写入数据失败!\"); return; void CChildView::OnChildRead() { char buf[100]={0}; DWORD dwRead; if(!ReadFile(hRead,buf,100,&dwRead,NULL)) { } AfxMessageBox(\"读取数据失败!\"); return; } AfxMessageBox(buf); void CChildView::OnChildWrite() { } char buf[]=\"子进程信息\"; DWORD dwWrite; if(!WriteFile(hWrite,buf,strlen(buf)+1,&dwWrite,NULL)) { } AfxMessageBox(\"写入数据失败!\"); return; 【实验结果截图】 本实验,在父进程的面板上,主要有创建管道,读,写,三个项目,子进程的项目上主 要有读,写,两个管道。由于电脑上没有VC++,第四题的源程序截图没办法重现,附上PPt中的图片。 【实验心得体会】 匿名管道一般用于实现本地父子进程之间的通信,其不能实现跨网络进程之间的通信,同时其也一般只用于实现父进程和子进程之间的通信。像匿名管道的话,其和邮槽不同,其可以实现父进程即可以向子进程发送数据,同时父进程又可以从子进程接收到数据。而且子进程可以接收来自父进程的数据,并且也可以给父进程发送数据。 实验五 信号量实现进程同步 【实验软硬件环境】 VC++ 【实验内容】 生产者进程生产产品,消费者进程消费产品。 当生产者进程生产产品时,如果没有空缓冲区可用,那么生产者进程必须等待消费 者进程释放出一个缓冲区。 当消费者进程消费产品时,如果缓冲区中没有产品,那么消费者进程将被阻塞,直 到新的产品被生产出来。 【实验程序及分析】 生产者进程: // Test4.cpp : Defines the entry point for the console application. // #include \"stdafx.h\" #include #define BUF_SIZE 1025 char szName[] = \"NameOfMappingObject\"; // 共享内存的名字 int main() { // 创建共享文件句柄 HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // 物理文件句柄 NULL, // 默认安全级别 PAGE_READWRITE, // 可读可写 0, // 高位文件大小 BUF_SIZE, // 地位文件大小 szName // 共享内存名称 ); char *pBuf = (char *)MapViewOfFile( hMapFile, // 共享内存的句柄 FILE_MAP_ALL_ACCESS, // 可读写许可 0, 0, BUF_SIZE ); if(hMapFile != NULL) cout<<\"Create Success\"< char szInfo[BUF_SIZE] = {0}; gets(szInfo); cout << \"write \"< pBuf[BUF_SIZE - 1] = '\\0'; } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; } 消费者进程: // Test4Get.cpp : Defines the entry point for the console application. // #include \"stdafx.h\" #include #define BUF_SIZE 1025 char szName[] = \"NameOfMappingObject\"; // 共享内存的名字 int main() { // 创建共享文件句柄 HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // 物理文件句柄 NULL, // 默认安全级别 PAGE_READWRITE, // 可读可写 0, // 高位文件大小 BUF_SIZE, // 地位文件大小 szName // 共享内存名称 ); char *pBuf = (char *)MapViewOfFile( hMapFile, // 共享内存的句柄 FILE_MAP_ALL_ACCESS, // 可读写许可 0, 0, BUF_SIZE ); cout<<\"Open Success\"< getchar(); cout << pBuf << endl; } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; } 【实验结果截图】 【实验心得体会】 通过自己手动编写生产者消费者程序,进一步了解了基本的进程同步与互斥 算法,理解生产者-消费者问题了解到同步对象是指Windows中用于实现同步与互斥的实体,包括信号量(Semaphore)、互斥量(Mutex)、临界区(Critical Section)和事件(Events)等。本实验中使用到信号量、互斥量和临界区三个同步对象。 实验六 共享主存实现进程通信 【实验软硬件环境】 VC++ 【实验内容】 建立父子进程,由父进程创建一个命名匿名管道,由子进程向命名管道写入数据,由 父进程从命名管道读取数据 【实验原理】 共享存储区(Share Memory)是UNIX系统中通信速度最高的一种通信机制。该机制 可使若干进程共享主存中的某一个区域,且使该区域出现(映射)在多个进程的虚地址空间中。另一方面,一个进程的虚地址空间中又可连接多个共享存储区,每个共享存储区都有自己的名字。当进程间欲利用共享存储区进行通信时,必须先在主存中建立一共享存储区,然后将它附接到自己的虚地址空间上。此后,进程对该区的访问操作,与对其虚地址空间的其它部分的操作完全相同。共享主存段在系统调用时,首先得申请一个共享主存段之后才能对共享存储进行操作。 应当指出,共享存储区机制只为进程提供了用于实现通信的共享存储区和对共享存储区进行操作的手段,然而并未提供对该区进行互斥访问及进程同步的措施。因而当用户需要使用该机制时,必须自己设置同步和互斥措施才能保证实现正确的通信。 对于已申请到通信所需要的共享段,进程需把它附加到自己的虚拟空间后才能对其进行写。 【实验程序及分析】 父进程部分代码: // // SharedStorage.cpp : Defines the entry point for the console application. // #include #define SIZE 1024 char name[] = \"sharedstorage\"; int main() { HANDLE mapFile = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,SIZE,name); char *mapView = (char *)MapViewOfFile(mapFile,FILE_MAP_ALL_ACCESS,0,0,SIZE); cout << \"input a string:\" << endl; char info[SIZE] = {0}; gets(info); strncpy(mapView, info, SIZE - 1); mapView[SIZE - 1] = '\\0'; UnmapViewOfFile(mapView); CloseHandle(mapFile); } 子进程部分代码: // //#include // SharedStorageRead.cpp : Defines the entry point for the console application. return 0; #include #define SIZE 1024 char name[] = \"sharedstorage\"; int main() { HANDLE mapFile = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,SIZE,name); char *mapView = (char *)MapViewOfFile(mapFile,FILE_MAP_ALL_ACCESS,0,0,SIZE); cout << \"press any key to continue:\" << endl; getchar(); cout << mapView << endl; UnmapViewOfFile(mapView); CloseHandle(mapFile); } return 0; 【实验结果截图】 【实验心得体会】 通过本次试验,掌握了对共享主存区的操作方法,了解了实现共享主存区时要实现 的一些步骤和细节,在学长的指导下,解决了一开始存在的数据读取不到的问题,对实现过程有了更多的认识。 因篇幅问题不能全部显示,请点此查看更多更全内容