实验二_进程间通信
《Linux操作系统设计实践》实验二:进程通信

《Linux操作系统设计实践》实验二:进程通信实验目的:进一步了解和熟悉 Linux 支持的多种 IPC 机制,包括信号,管道,消息队列,信号量,共享内存。
实验环境: redhat实验内容:(1)进程间命名管道通信机制的使用:使用命名管道机制编写程序实现两个进程间的发送接收信息。
(2)进程间消息队列通信机制的使用:使用消息队列机制自行编制有一定长度的消息(1k 左右)的发送和接收程序。
(3)进程间共享存储区通信机制的使用:使用共享内存机制编制一个与上述(2)功能相同的程序。
并比较分析与其运行的快慢。
实验代码验证:(1).使用命名管道机制编写程序实现两个进程间的发送接收信息。
#include <stdio.h>#include <stdlib.h>#define FIFO_FILE "MYFIFO"int main(int argc, char *argv[]){FILE *fp;int i;if (argc<=1){printf("usage: %s <pathname>\n",argv[0]); exit(1);}if ((fp = fopen(FIFO_FILE, "w")) == NULL) {printf("open fifo failed. \n");exit(1);}for (i = 1; i < argc; i++){if (fputs(argv[i],fp) == EOF){printf("write fifo error. \n");exit(1);}if (fputs(" ",fp) == EOF){printf("write fifo error. \n"); exit(1);}}fclose(fp);return 0;}#include <stdio.h>#include <stdlib.h>#include <sys/stat.h>#include <unistd.h>#include <linux/stat.h>#define FIFO_FILE "MYFIFO"int main(){FILE *fp;char readbuf[80];if ((fp = fopen(FIFO_FILE, "r")) == NULL) {umask(0);mknod(FIFO_FILE, S_IFIFO | 0666, 0);}else{fclose(fp);}while (1){if ((fp = fopen(FIFO_FILE, "r")) == NULL) {printf("open fifo failed. \n");exit(1);}if (fgets(readbuf, 80, fp) != NULL){printf("Received string :%s \n", readbuf); fclose(fp);}else{if (ferror(fp)){printf("read fifo failed.\n");exit(1);}}}return 0;}实验结果:Server.c将client.c写入的字符输出。
实验二.进程间通信

实验题目:进程间通信实验目的:理解进程间通信、进程同步与互斥实验内容:有一个名为DATA的文本文件,其中只含有一行文本,该文本内容为一个ASCII码格式的正整数。
现在有多个进程,它们都要访问DATA文件,具体操作是读出整数、对其加1、然后将整数存回到文件之中。
现在要求编写程序,能够正确地实现这一操作。
显然,如果对上述的多个进程同时操作一个整数的行为不加以控制,则会产生竞争条件,导致错误的运行结果。
(一)请使用文件上锁的办法,编写C语言程序,解决竞争条件问题。
(二)请使用信号量解决上述问题作为参考,下面给出了一个不上锁的程序#include <stdio.h>#include <stdlib.h>#include <fcntl.h>#include <sys/types.h>#include <unistd.h>#include <stdarg.h>#include <string.h>int main(void){int num, fd,i;FILE *f;char buff[100];fd = open("data", O_RDWR);f = (FILE *)fdopen(fd, "r+");for(i=1;i<=100000;i++){lseek(fd, 0, SEEK_SET);fscanf(f, "%d", &num);sprintf(buff, "%d\n", num + 1);lseek(fd, 0, SEEK_SET);write(fd, buff,strlen(buff));}fclose(f);return 0;}信号量请使用信号量机制代替文件锁,实现文件的互斥访问。
作为参考,给同学们提供一个演示程序,这个程序中,父进程创建子进程之后,父子进程并发执行。
操作系统实验2 进程通信

仲恺农业工程学院实验报告纸
计算机科学与工程(院、系)网络工程专业班组《操作系统》
学号姓名实验日期2011-5-24 教师评定
实验二进程通信
一.实验目的:
通过实验使学生进一步了解进程之间的各种通信方式、基本原理和不同操作系统中具体的实现。
基本能达到下列具体的目标:
1、理解进程消息通信的概念,如何实现两个创建进程之间的数据传递。
2、理解进程共享变量的进程通信。
二.实验内容:
1.选择Window或Linux,并选择该操作系统中一种进程通信的方式。
2.查找该进程通信的API使用方式,设计出一个合适的应用程序。
3.采用java语言实现该应用程序。
三.实验步骤:
这里可以实现两个人在同一局域网的聊天,程序可以自动扫描上线的用户。
如果需要与其中的用户进行交谈,则只需双击用户列表,输入对方IP,便可在下面的输入框内输入信息进行发送。
这个是三个人之间进行交谈,但是只能够实现相互两个人之间进行通信,方式跟上面的差不多。
但是三个人都可以看到发送的信息。
本机上的交谈信息
其他用户上的信息
四.实验心得:
这次的实验一开始是在课上有简单的弄了下,后来跟计算机网络的课程设计题目——聊天软件设计差不多一致,于是便这个当做了课题来进行课程设计,通过实现简单的聊天程序来完成进程间的通信。
这次的实验采用基于Java的程序设计技术,要用到很多Java socket的知识。
刚开始也得从网上找一些代码来看和了解一些新的知识。
操作系统实验 进程与进程通信

计算机工程学院实验报告课程名称:操作系统实验班级实验成绩:指导教师:姓名:实验项目名称:进程与进程通信学号:上机实践日期:2009-11-13实验项目编号:实验二组号:上机实践时间:2学时一、目的1、深刻理解进程和线程的概念;2、掌握线程和进程的差别以及与之相适应的通信方式;3、掌握在Linux环境下创建进程: fork()的应用;4、了解用fork()创建进程、以及整个程序的运行过程;5、掌握多进程的程序设计与进程之间通信的方法;6、掌握共享内存、信号灯集实现进程通信的方法;7、理解、掌握Linux下文件系统,以及其安装与卸载过程。
二、实验内容1、在Linux环境下,用fork()创建多个进程,分别运行不同的函数;2、一部分进程代表读者,一部分进程代表写者;用共享内存、信号灯集机制实现各个读者、写者进程之间的通信;3、掌握shmget()、shmat()、shmctl()以及semget()、semctl()、semop()等函数在进程通信中的使用方法;4、用信号灯加PV操作实现进程间的互斥与同步。
三、实验环境1、操作系统:Red Hat Linux四、实验原理1、枚举数据类型,在信号灯集初始化时使用。
该结构在sys/sem.h中没有定义,必须程序设计者自行定义。
其中:semid—已经创建的信号灯集ID,sn—操作的元素的IDunion semun{int val;struct semid_ds *buf;ushort *array;};2、对信号灯集中的某个元素进行P操作。
首先要定义一个sembuf 类型的变量(该类型已经在sys/sem.h中预定义,可以直接引用),然后对该变量的各个元素进行赋值,注意进行P操作,主要是sem_op元素赋值为 -1。
其中:semid—已经创建的信号灯集ID,sn—操作的元素的IDvoid down(int semid,int sn){/* define P operating*/struct sembuf op;op.sem_num=sn;op.sem_op=-1;op.sem_flg=0;semop(semid,&op,1);}3、对信号灯集中的某个元素进行V操作。
实验二 进程间通讯 实验报告

Linux信号量实验报告一、实验目的深入理解操作系统中进程间通讯的本质二、实验方法利用UNIX/LINUX所提供的信号量、共享存储器、PV操作、文件锁等机制实现进程间的信息共享、进程间的互斥与同步。
三、实验任务编写一个C语言程序,该程序将一个存放了一个整数的文本文件内容执行加1操作一百万次,同时启动这个程序的多个副本,观察执行结果是否正确。
利用信号量机制对文件上锁,重新运行观察结果是否正确。
四、实验要点信号量概念、PV操作五、实验内容5.1 信号量概念信号量是一种确保特定代码段(临界区)只能被一个进程或者线程调用的一种机制。
在实际应用中,信号量由一种特殊的数据结构——信号量集所管理。
在使用信号量以前,需要创建一个信号量集,使用完成以后需要销毁信号量集。
信号量集的作用相当于一个信号量的计数器。
P操作是向信号量集获取一个信号量的操作,如果此时信号量集中有信号量,则会对信号量中的计数器进行更改(大部分情况下是计数器减一);如果此时信号量集中没有可用信号量(即计数器为0时),则执行P操作的线程或者进程则会被阻塞,直到信号量集中拥有可用的信号量(即计数器不为0)。
具体关系可用下图表示:5.2 信号量的初始化信号量的初始化需要用到两个函数(semget和semctl)和一个联合体结构(该实验中我们只需要用联合体结构中的val值,所以我只定义val变量)。
Semget系统调用的定义如下:int semget(key_t key, int nsems, int semflg)semget这个系统调用的作用是返回一个与key参数相关联的一个信号量集标识,semflg 参数会控制函数的行为;如果semflg为IPC_CREAT或者IPC_PRIVATE,则函数会创建一个拥有nsems个信号量的信号量集;如果semflg的值为IPC_CREAT | IPC_EXCL,在信号量集已经存在的情况下会发生错误。
实验中使用的获得信号量集标识的代码为:int sem_id = semget((key_t)2234, 0, 0);if (sem_id == -1){sem_id = semget((key_t)2234, 1, 0666 | IPC_CREAT);if (!init(sem_id)) return -1;}上述代码的第一行,nsems和semflg参数均为0,目的是只获得与2234这个值相关联的信号量集的标识;如果这个信号量集已经存在,则返回这个信号量集的标识;否则返回-1 下面就对获得的sem_id进行判断,如果值为-1,即信号量集还没有被创建,需要创建一个信号量集。
进程实验-进程间通信(管道、消息、共享内存、软中断)

进程实验3 Linux 进程间通信一、软中断信号的处理,实现同一用户的各进程之间的通信。
●相关的系统调用⏹kill(pid ,sig):发送信号⏹signal(sig, func):指定进程对信号sig的处理行为是调用函数func。
●程序清单#include <unistd.h>#include <stdio.h>#include <signal.h>void waiting();void stop();int wait_mark;main(){int p1,p2;while((p1=fork())==-1);if(p1>0){while((p2=fork())==-1);if(p2>0){ printf("parent\n");/*父进程在此完成某个操作、或接收到用户从键盘输入的特殊按键命令后发出下面的信号。
这里省略。
*/kill(p1,16);kill(p2,17);wait(0);wait(0);printf("parent process id killed! \n");exit(0);}else/* p2==0*/{printf("p2\n");wait_mark=1;signal(17,stop);waiting();printf("child process 2 is killed by parent! \n");exit(0);}}else/*p1==0*/{printf("p1\n");wait_mark=1;signal(16,stop);waiting();printf("child process 1 is kelled by parent! \n");exit(0);}}void waiting(){while(wait_mark!=0);}void stop(){wait_mark=0;}●输入并运行此程序,分析程序的运行结果。
试验二进程通信Linux试验报告

实验报告学号姓名成绩__________实验二进程通信【实验目的和要求】1、了解进程通信的概念及方法;2、了解信号量、管道;3、掌握信号量、管道和命名管道编程方法。
【实验内容】1、利用命名管道实现单机QQ聊天;2、撰写实验报告;【实验原理】1、信号量(semaphore)是为那些访问相同资源的进程以及同一进程不同线程之间提供的一个同步机制。
它不是用于传输数据,而只是简单地协调对共享资源的访问。
信号量包含一个计数器,表示某个资源正在被访问和访问的次数,用来控制多进程对共享数据的访问。
一旦成功拥有了一个信号量,对它所能做的操作只有两种:请求和释放。
当执行释放操作时,系统将该信号值减1(如果小于零,则设置为零);当执行请求操作时,系统将该信号值加1,如果加1后的值大于设定的最大值,那么系统将会挂起处理进程,直到信号值小于最大值为止。
Tuxedo 用信号量来确保在某一时刻只有一个进程对某一块共享内存进程访问。
信号量配置太低会导致Tuxedo系统应用程序无法启动。
2、管道分为两种:管道和命名管道。
管道是UNIX系统IPC的最古老形式,并且所有的UNIX系统都提供这种通信机制。
可以在有亲缘关系(父子进程或者是兄弟进程之间)进行通信,管道的数据只能单向流动,如果想双向流动,必须创建两个管道。
管道应用的一个重大缺陷就是没有名字,因此只能用于亲缘进程之间的通信。
后来以管道为基础提出命名管道(namedpipe,FIFO)的概念,该限制得到了克服。
FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。
这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间),因此,通过FIFO不相关的进程也能交换数据。
值得注意的是,FIFO严格遵循先进先出(first in first out)规则,对管道及FIFO的读总是从开始处返回数据,对它们的写则是把数据添加到末尾。
进程通讯管理实验报告(3篇)

第1篇一、实验目的1. 理解进程通信的概念和原理;2. 掌握进程通信的常用机制和方法;3. 能够使用进程通信机制实现进程间的数据交换和同步;4. 增强对操作系统进程管理模块的理解。
二、实验环境1. 操作系统:Linux2. 编程语言:C3. 开发环境:GCC三、实验内容1. 进程间通信的管道机制2. 进程间通信的信号量机制3. 进程间通信的共享内存机制4. 进程间通信的消息队列机制四、实验步骤1. 管道机制(1)创建管道:使用pipe()函数创建管道,将管道文件描述符存储在两个变量中,分别用于读和写。
(2)创建进程:使用fork()函数创建子进程,实现父子进程间的通信。
(3)管道读写:在父进程中,使用read()函数读取子进程写入的数据;在子进程中,使用write()函数将数据写入管道。
(4)关闭管道:在管道读写结束后,关闭对应的管道文件描述符。
2. 信号量机制(1)创建信号量:使用sem_open()函数创建信号量,并初始化为1。
(2)获取信号量:使用sem_wait()函数获取信号量,实现进程同步。
(3)释放信号量:使用sem_post()函数释放信号量,实现进程同步。
(4)关闭信号量:使用sem_close()函数关闭信号量。
3. 共享内存机制(1)创建共享内存:使用mmap()函数创建共享内存区域,并初始化数据。
(2)映射共享内存:在父进程和子进程中,使用mmap()函数映射共享内存区域。
(3)读写共享内存:在父进程和子进程中,通过指针访问共享内存区域,实现数据交换。
(4)解除映射:在管道读写结束后,使用munmap()函数解除映射。
4. 消息队列机制(1)创建消息队列:使用msgget()函数创建消息队列,并初始化消息队列属性。
(2)发送消息:使用msgsnd()函数向消息队列发送消息。
(3)接收消息:使用msgrcv()函数从消息队列接收消息。
(4)删除消息队列:使用msgctl()函数删除消息队列。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验二 进程间通信一、实验目的 在本实验中,通过对文件映射对象的了解,来加深对 Windows 2000 线程同步的理解. 回顾系统进程、线程的有关概念,加深对 Windows 2000 线程间通讯的理解;了解文件映射 对象;通过分析实验程序,了解线程如何通过文件映射对象发送数据;了解在进程中如何使 用文件映射对象. 二、背景知识 1. 共享内存: Windows 2000 提供了一种在文件中处理数据的方法, 名为内存映射文件, 也称为文件映射.文件映射对象是在虚拟内存中分配的永久或临时文件对象区域 (如果可能 的话,可大到整个文件) ,可将其看作是二进制的数据块.使用这类对象,可获得直接在内 存中访问文件内容的能力. 文件映射对象提供了强大的扫描文件中数据的能力,而不必移动文件指针.对于多线程 的读写操作来说, 这一点特别有用, 因为每个线程都可能想要把读取指针移动到不同的位置 去——为了防止这种情况,就需要使用某种线程同步机制保护文件. 在 CreateFileMapping() API 中,一个新的文件映射对象需要有一个永久的文件对象 (由 CreateFile() 所创建) .该函数使用标准的安全性和命名参数,还有用于允许操作 (如只读) 的保护标志以及映射的最大容量.随后可根据来自 OpenFileMapping() API 的其他线程或进程 使用该映射——这与事件和互斥体的打开进程是非常类似的. 内存映射文件对象的另一个强大的应用是可请求系统创建一个运行映射的临时文件.该 临时文件提供一个临时的区域, 用于线程或进程互相发送大量数据, 而不必创建或保护磁盘 上的文件.利用向创建函数中发送 INVALID_HANDLE_VALUE 来代替真正的文件句柄,就 可创建这一临时的内存映射文件; 指令内核使用系统页式文件来建立支持映射的最大容量的 临时数据区. 为了利用文件映射对象,进程必须将对文件的查看映射到它的内存空间中.也就是说, 应该将文件映射对象想象为进程的第一步,在这一步中,当查看实际上允许访问的数据时, 附加有共享数据的安全性和命名方式.为了获得指向内存区域的指针需要调用 MapViewOfFile() API,此调用使用文件映射对象的句柄作为其主要参数.此外还有所需的访 问等级 (如读-写) 和开始查看时文件内的偏移和要查看的容量.该函数返回一个指向进程内 的内存的指针,此指针可有多种编程方面的应用 (但不能超过访问权限) . 当结束文件映射查看时,必须用接受到的指针调用 UnmapViewOfFlie() API,然后再根 据映射对象调用 CloseHandle() API,从而将其清除。
三、实验内容 1. 编译运行项目 Lab5.1\SHAREMEM.DSW,观察运行结果,并阅读和分析实验程序.2. Lab5.2 目录下的示例程序:ProcessA.exe,ProcessB.exe 用三种方法实现了进程通信. (1)进程 A 中输入一些字符,点“利用 SendMessage 发送消息”按钮可将消息发到进程 B. (2)在进程 A 中输入一些字符,点“写数据到内存映像文件”按钮,然后在进程 B 中点“从 内存映像文件读数据” 按钮可收到消息. (3)先在进程 B 中点“创建管道并接收数据” 按钮,然后在进程 A 中输入一些字符,点“写 数据到管道文件”按钮可将消息发到进程 B(重复第 3 步每次可发一条消息). 消息传递数据通信可参考 SendMessage.txt,共享内存通信可参考 MemFile.txt,管道 通信可参考 Pipe.txt. 3.编写程序利用 WM_COPYDATA 消息机制,实现线程间的通信.进程间通信之管道每个进程各自有不同的用户地址空间, 任何一个进程的全局变量在另一个进程中 都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区, 进程 1 把数据从用户空间拷到内核缓冲区,进程 2 再从内核缓冲区把数据读走, 内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。
如下图所示。
图 3.1 进程间通信3.1 管道管道是一种最基本的 IPC 机制,由 pipe 函数创建:#include <unistd.h>int pipe(int filedes[2]);调用 pipe 函数时在内核中开辟一块缓冲区(称为管道)用于通信,它有一个读 端一个写端, 然后通过 filedes 参数传出给用户程序两个文件描述符, filedes[0] 指向管道的读端,filedes[1]指向管道的写端(很好记,就像 0 是标准输入 1 是标准输出一样)。
所以管道在用户程序看起来就像一个打开的文件,通过 read(filedes[0]);或者 write(filedes[1]);向这个文件读写数据其实是在读 写内核缓冲区。
pipe 函数调用成功返回 0,调用失败返回-1。
开辟了管道之后如何实现两个进程间的通信呢?比如可以按下面的步骤通信。
图 3.2 管道1. 父进程调用 pipe 开辟管道, 得到两个文件描述符指向管道的两端。
2. 父进程调用 fork 创建子进程,那么子进程也有两个文件描述符指 向同一管道。
3. 父进程关闭管道读端,子进程关闭管道写端。
父进程可以往管道里 写,子进程可以从管道里读,管道是用环形队列实现的,数据从写 端流入从读端流出,这样就实现了进程间通信。
例、管道#include <stdlib.h> #include <unistd.h> #define MAXLINE 80int main(void) { int n; int fd[2]; pid_t pid; char line[MAXLINE];if (pipe(fd) < 0) { perror("pipe"); exit(1); } if ((pid = fork()) < 0) { perror("fork"); exit(1); } if (pid > 0) { /* parent */ close(fd[0]); write(fd[1], "hello world\n", 12); wait(NULL);} else {/* child */close(fd[1]); n = read(fd[0], line, MAXLINE);write(STDOUT_FILENO, line, n); } return 0; }使用管道有一些限制: 两个进程通过一个管道只能实现单向通信,比如上面的例子,父进 程写子进程读, 如果有时候也需要子进程写父进程读,就必须另开 一个管道。
请读者思考,如果只开一个管道,但是父进程不关闭读 端,子进程也不关闭写端,双方都有读端和写端,为什么不能实现 双向通信? 管道的读写端通过打开的文件描述符来传递,因此要通信的两个进 程必须从它们的公共祖先那里继承管道文件描述符。
上面的例子是 父进程把文件描述符传给子进程之后父子进程之间通信, 也可以父 进程 fork 两次,把文件描述符传给两个子进程,然后两个子进程 之间通信,总之需要通过 fork 传递文件描述符使两个进程都能访 问同一管道,它们才能通信。
使用管道需要注意以下 4 种特殊情况(假设都是阻塞 I/O 操作,没有设置 O_NONBLOCK 标志): 1. 如果所有指向管道写端的文件描述符都关闭了 (管道写端的引用计 数等于 0),而仍然有进程从管道的读端读数据,那么管道中剩余 的数据都被读取后,再次 read 会返回 0,就像读到文件末尾一样。
2. 如果有指向管道写端的文件描述符没关闭 (管道写端的引用计数大 于 0),而持有管道写端的进程也没有向管道中写数据,这时有进 程从管道读端读数据,那么管道中剩余的数据都被读取后,再次 read 会阻塞,直到管道中有数据可读了才读取数据并返回。
3. 如果所有指向管道读端的文件描述符都关闭了 (管道读端的引用计 数等于 0),这时有进程向管道的写端 write,那么该进程会收到 信号 SIGPIPE,通常会导致进程异常终止。
4. 如果有指向管道读端的文件描述符没关闭 (管道读端的引用计数大 于 0),而持有管道读端的进程也没有从管道中读数据,这时有进 程向管道写端写数据,那么在管道被写满时再次 write 会阻塞,直 到管道中有空位置了才写入数据并返回。
管道的这四种特殊情况具有普遍意义。
3.2 其它 IPC 机制进程间通信必须通过内核提供的通道, 而且必须有一种办法在进程中标识内核提 供的某个通道, 上一节讲的管道是用打开的文件描述符来标识的。
如果要互相通 信的几个进程没有从公共祖先那里继承文件描述符, 它们怎么通信呢?内核提供 一条通道不成问题, 问题是如何标识这条通道才能使各进程都可以访问它?文件 系统中的路径名是全局的, 各进程都可以访问,因此可以用文件系统中的路径名 来标识一个 IPC 通道。
FIFO 和 UNIX Domain Socket 这两种 IPC 机制都是利用文件系统中的特殊文件 来标识的。
可以用 mkfifo 命令创建一个 FIFO 文件:$ mkfifo hello $ ls -l hello prw-r--r-- 1 akaedu akaedu 0 2008-10-30 10:44 helloFIFO 文件在磁盘上没有数据块,仅用来标识内核中的一条通道,各进程可以打 开这个文件进行 read/write, 实际上是在读写内核通道 (根本原因在于这个 file 结构体所指向的 read、write 函数和常规文件不一样),这样就实现了进程间通 信。
UNIX Domain Socket 和 FIFO 的原理类似,也需要一个特殊的 socket 文件 来标识内核中的通道,例如/var/run 目录下有很多系统服务的 socket 文件:$ ls -l /var/run/ total 52 srw-rw-rw- 1 root root 2008-10-30 00:24 acpid.socket ... 0srw-rw-rw- 1 root root 2008-10-30 00:25 gdm_socket ... srw-rw-rw- 1 root 2008-10-30 00:24 sdp ... srwxr-xr-x 1 root root 2008-10-30 00:42 synaptic.socket root000文件类型 s 表示 socket, 这些文件在磁盘上也没有数据块。