Linux进程间通信(2)实验报告
- 格式:docx
- 大小:25.37 KB
- 文档页数:8
软件学院计算机课程实验报告册课程名称计算机操作系统实验学期 2011 年至 2012 年第 2 学期学生所在院(系)软件学院年级 11软件专业班级软工(1)班学生姓名朱水云学号 **********指导教师陈自刚实验最终成绩软件学院实验室制2012 年 4 月实验报告( 二 ) 实验名称:进程间通信实验时间:2012年4月18号实验性质应用性设计性综合性5,观察运行结果,并思考6,退出中断并写出实验报告调试过程:根据编译提示的错误进行修改四、实验结果:1消息的发送和接受运行结果:2.共享存储区的创建、附接和段接运行结果:五、疑难与小结:1.消息的创建,发送和接收小结:从理想的结果来说,应当是每当Client发送一个消息后,server 接收该消息,Client再发送下一条。
也就是说“(Client)sent”和“(server)received”的字样应该在屏幕上交替出现。
实际的结果大多是,先由 Client 发送两条消息,然后Server接收一条消息。
此后Client Server交替发送和接收消息.最后一次接收两条消息. Client 和Server 分别发送和接收了10条消息,与预期设想一致message的传送和控制并不保证完全同步,当一个程序不再激活状态的时候,它完全可能继续睡眠,造成上面现象,在多次send message 后才 receive message.这一点有助于理解消息转送的实现机理.2.共享存储区的创建、附接和段接运行的结果和预想的完全一样。
但在运行的过程中,发现每当client 发送一次数据后,server要等大约0.1秒才有响应。
同样,之后client又需要等待大约0.1秒才发送下一个数据。
出现上述的应答延迟的现象是程序设计的问题。
当client端发送了数据后,并没有任何措施通知server端数据已经发出,需要由client的查询才能感知。
此时,client端并没有放弃系统的控制权,仍然占用CPU的时间片。
《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写入的字符输出。
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,即信号量集还没有被创建,需要创建一个信号量集。
实验二 Linux进程通信一、实验目的1)了解有关Linux系统调用;2)学习有关Linux的进程创建,理解进程创建后两个并发进程的执行。
二、实验内容在Linux环境下,用C/C++语言编程,使用系统调用fork创建进程多个子进程。
(1) 调试并完成下列程序,完成实验要求:#include "stdio.h"#include "sys/types.h"#include "unistd.h"int main(){pid_t pid1;pid_t pid2;pid1 = fork();pid2 = fork();printf("pid1:%d, pid2:%d\n", pid1, pid2);}要求:A.请说出执行这个程序后,将一共运行几个进程。
B.观察运行结果,并给出分析与解释。
答:A.执行这个程序后,将一共运行4个进程。
A.运行结果如下:分析与解释:fork()函数能够建立子进程,且使得子进程得到父进程地址空的一个复制;而且,当创建成功时,如果是父进程则返回0,子进程则返回子进程的I D,但是,fork()创建的进程并不是从该程序开头开始执行,它只是和父进程一样继续执行后续代码,因此在之后的语句中,父子进程同时创建一个进程,就形成了四个进程,如图上所示。
所以,,在上面的截图中,第一次fork()函数时成功产生了父子进程pid分别为2775和0,第二次使用fork()函数时父子进程又各产生了一对父子进程父进程产生的父子进程的pid分别为2776和0,子进程产生的父子进程的pid分别为0和2777。
因为进程是并发的,他的调度我们无法干预,所以出现的结果并非都是一成不变的,执行多次后,输出的顺序有可能不一样。
(2)参考下面的相关程序实例,编写一个管道实验程序,实现两个进程之间的数据通信。
要求:父进程顺序写入若干个字符串,子进程顺序读出内容,并写入文件piple.txt,并显示出来。
实验报告学号姓名成绩__________实验二进程通信【实验目的和要求】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的读总是从开始处返回数据,对它们的写则是把数据添加到末尾。
一、实验目的1. 理解进程通信的概念和作用。
2. 掌握进程通信的常用方法,包括管道、消息队列、信号量等。
3. 通过编程实践,加深对进程通信机制的理解和应用。
二、实验环境操作系统:Linux开发环境:gcc三、实验内容1. 管道通信2. 消息队列通信3. 信号量通信四、实验步骤及分析1. 管道通信(1)实验步骤1)创建一个父进程和一个子进程;2)在父进程中创建一个管道,并将管道的读端和写端分别赋给父进程和子进程;3)在父进程中,通过管道的写端发送数据给子进程;4)在子进程中,通过管道的读端接收父进程发送的数据;5)关闭管道的读端和写端;6)结束进程。
(2)实验分析通过管道通信,实现了父进程和子进程之间的数据传递。
管道是半双工通信,数据只能单向流动。
在本实验中,父进程向子进程发送数据,子进程接收数据。
2. 消息队列通信(1)实验步骤1)创建一个消息队列;2)在父进程中,向消息队列中发送消息;3)在子进程中,从消息队列中接收消息;4)删除消息队列;5)结束进程。
(2)实验分析消息队列是一种进程间通信机制,允许不同进程之间传递消息。
消息队列的创建、发送、接收和删除等操作都是通过系统调用实现的。
在本实验中,父进程向消息队列发送消息,子进程从消息队列接收消息,实现了进程间的消息传递。
3. 信号量通信(1)实验步骤1)创建一个信号量;2)在父进程中,对信号量执行P操作,请求资源;3)在子进程中,对信号量执行V操作,释放资源;4)结束进程。
(2)实验分析信号量是一种用于实现进程同步的机制。
在进程通信中,信号量可以用来协调多个进程对共享资源的访问。
在本实验中,父进程和子进程通过信号量实现了对共享资源的同步访问。
五、实验结果1. 管道通信实验结果:父进程成功向子进程发送数据,子进程成功接收数据。
2. 消息队列通信实验结果:父进程成功向消息队列发送消息,子进程成功从消息队列接收消息。
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、掌握信号量、管道和命名管道编程方法。
【实验内容】1、利用命名管道实现单机QQ聊天;2、撰写实验报告;【实验原理】1、信号量(semaphore)是为那些访问相同资源的进程以及同一进程不同线程之间提供的一个同步机制。
它不是用于传输数据,而只是简单地协调对共享资源的访问。
信号量包含一个计数器,表示某个资源正在被访问和访问的次数,用来控制多进程对共享数据的访问。
一旦成功拥有了一个信号量,对它所能做的操作只有两种:请求和释放。
当执行释放操作时,系统将该信号值减1(如果小于零,则设置为零);当执行请求操作时,系统将该信号值加1,如果加1后的值大于设定的最大值,那么系统将会挂起处理进程,直到信号值小于最大值为止。
Tuxedo 用信号量来确保在某一时刻只有一个进程对某一块共享内存进程访问。
信号量配置太低会导致Tuxedo系统应用程序无法启动。
2、管道分为两种:管道和命名管道。
管道是UNIX系统IPC的最古老形式,并且所有的UNIX系统都提供这种通信机制。
可以在有亲缘关系(父子进程或者是兄弟进程之间)进行通信,管道的数据只能单向流动,如果想双向流动,必须创建两个管道。
管道应用的一个重大缺陷就是没有名字,因此只能用于亲缘进程之间的通信。
后来以管道为基础提出命名管道(named pipe,FIFO)的概念,该限制得到了克服。
FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。
这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间),因此,通过FIFO不相关的进程也能交换数据。
值得注意的是,FIFO严格遵循先进先出(first in first out)规则,对管道及FIFO的读总是从开始处返回数据,对它们的写则是把数据添加到末尾。
实验三2_Linux进程间通信实验三 Linux进程间通信一、实验目的熟悉Linux下进程间通信机制,能够使用系统提供的各种通信机制实现并发进程间的数据交换。
二、实验题目分别使用Linux下的共享存储区、消息、管道等通信机制,编程实现并发进程之间的相互通信。
三、背景材料(一)需要用到的系统调用实验可能需要用到的主要系统调用和库函数在下面列出,详细的使用方法说明通过“man 2 系统调用名”或者“man 3 函数名”命令获取。
fork() 创建一个子进程,通过返回值区分是在父进程还是子进程中执行;wait() 等待子进程执行完成;getpid() 获取当前进程id;shmget() 建立一个共享存储区;shmctl() 操纵一个共享存储区;shmat() 把一个共享存储区附接到进程内存空间;shmdt() 把一个已经附接的共享存储区从进程内存空间断开;msgget() 建立一个消息队列;msgctl() 操纵一个消息队列;msgsnd() 发送消息;msgrcv() 接收消息;signal() 设置对信号的处理方式或处理过程;pipe() 打开管道;lockf() 锁定一个文件。
(二)使用共享存储区的示例程序下面程序主要用来演示共享存储区的使用方法:首先要使用shmget得到共享存储区句柄(可以新建或连接已有的共享存储区,以关键字标识),然后使用shmat挂接到进程的存储空间(这样才能够访问),当使用完后,使用shmctl释放(shmctl 还可以完成一些其他功能)。
这种使用逻辑也适用于消息和信号量。
示例程序代码如下:#include <sys/types.h>#include <unistd.h>#include <stdio.h>#include <sys/ipc.h>#include <sys/shm.h>int main(void){int x, shmid;int *shmptr;if((shmid=shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT|0666)) < 0) printf("shmget error"), exit(1);//函数原型int shmget(key_t key,int size,int shmflg); 函数用于创建(或者获取)一key键值指定的共享内存对象,返回该对象的系统标识符:shmid;size 是创个由IPC_CREAT|0666,说明新建一个权限为0666的消息队列,建的共享内存的大小,id,若其中组用户、当前用户以及其他用户拥有读写的权限若成功则返回共享内存-1 出错则为if((shmptr=(int *)shmat(shmid, 0, 0)) == (int *)-1)printf("shmat error"), exit(1);// void *shmat(int shm_id,void *shm_addr,int shmflg); shm_id标识码,shm_addr连,shmflg标志位接到的地址printf("Input a initial value for *shmptr: ");scanf("%d", shmptr);while((x=fork())==-1);if(x==0) /* child run */{printf("When child runs, *shmptr=%d\n", *shmptr);printf("Input a value in child: ");scanf("%d", shmptr);printf("*shmptr=%d\n", *shmptr);}else /* parent run */{wait();printf("After child runs, in parent, *shmptr=%d\n", *shmptr);if ( shmctl(shmid, IPC_RMID, 0) < 0 )// shmctl()函数声明:int shmctl(int shmqid, int cmd, struct shmid_ds *buf);返回值:0 on success函数用于对已创建的共享内存对象进行查询、设值、删除等操作;这个函数-1 on error:和 msgget()函数十分相似,用法也相同。
实验六:Linux进程间通信(2)(4课时)实验目的:理解进程通信原理;掌握进程中信号量、共享内存、消息队列相关的函数的使用。
实验原理:Linux下进程通信相关函数除上次实验所用的几个还有:信号量信号量又称为信号灯,它是用来协调不同进程间的数据对象的,而最主要的应用是前一节的共享内存方式的进程间通信。
要调用的第一个函数是semget,用以获得一个信号量ID。
int semget(key_t key, int nsems, int flag);key是IPC结构的关键字,flag将来决定是创建新的信号量集合,还是引用一个现有的信号量集合。
nsems是该集合中的信号量数。
如果是创建新集合(一般在服务器中),则必须指定nsems;如果是引用一个现有的信号量集合(一般在客户机中)则将nsems指定为0。
semctl函数用来对信号量进行操作。
int semctl(int semid, int semnum, int cmd, union semun arg);不同的操作是通过cmd参数来实现的,在头文件sem.h中定义了7种不同的操作,实际编程时可以参照使用。
semop函数自动执行信号量集合上的操作数组。
int semop(int semid, struct sembuf semoparray[], size_t nops);semoparray是一个指针,它指向一个信号量操作数组。
nops规定该数组中操作的数量。
ftok原型如下:key_t ftok( char * fname, int id )fname就是指定的文件名(该文件必须是存在而且可以访问的),id是子序号,虽然为int,但是只有8个比特被使用(0-255)。
当成功执行的时候,一个key_t值将会被返回,否则 -1 被返回。
共享内存共享内存是运行在同一台机器上的进程间通信最快的方式,因为数据不需要在不同的进程间复制。
通常由一个进程创建一块共享内存区,其余进程对这块内存区进行读写。
2011-2012学年第一学期计算机操作系统实验报告专业:班级:学号:姓名:提交日期:2011年11月1实验二Linux进程创建与进程通信【实验目的】1. 熟悉有关Linux系统调用;2. 学习有关Linux的进程创建,理解进程创建后两个并发进程的执行;3. 通过系统调用wait()和exit(),实现父子进程同步;4. 掌握管道、消息缓冲等进程通信方法并了解其特点和使用限制。
【实验内容】1. 父进程创建子进程实现父进程创建一个子进程,返回后父子进程分别循环输出字符串“The parent process.”及“The child process.”5次,每次输出后使用sleep(1)延时一秒,然后再进入下一次循环。
给出源程序代码和运行结果。
程序代码:main(){int p1,i;while ((p1=fork())==-1);if (p1>0)for (i=0;i<5;i++){printf("I am parent.\n");sleep(1);}elsefor (i=0;i<5;i++){printf("I am child.\n");sleep(1);}}运行结果:The parent process.The child process.The parent process.The child process.The parent process.The child process.The parent process.The child process.The parent process.The child process.2. 父子进程同步修改上题程序,使用exit()和wait()实现父子进程同步,其同步方式为父进程等待子进程的同步,即:子进程循环输出5次,然后父进程再循环输出5次。
给出源程序代码和运行结果。
程序代码:main(){int p1,i;while ((p1=fork())==-1);if (p1>0){wait(0);for (i=0;i<5;i++){printf("I am parent.\n");sleep(1);}}else{for (i=0;i<5;i++){printf("I am child.\n");sleep(1);}exit(0);}}运行结果:I am parent.I am parent.I am parent.I am parent.I am parent.I am child.I am child.I am child.I am child.I am child.3. Linux管道通信编写一个程序,实现以下功能。
实验二Linux进程间通信1.实验目的(1)分析进程争用临界资源的现象,学习解决进程互斥的方法;(2)学习如何利用进程的“软中断”、管道机制进行进程间的通信,并加深对上述通信机制的理解;(3)了解系统调用pipe( )、msgget( )、msgsnd( )、msgrcv( )、msgctl( )、shmget( )、shmat( )、shmdt( )、shmctl( )的功能和实现过程,利用共享存储区机制进行进程间通信。
2.实验内容(1)进程的控制编写一段程序,使用系统调用fork()创建两个子进程。
各进程循环显示不同的信息(如20次):父进程显示:“parent:”加上进程ID,子进程分别显示:“Child1:”(或“Child2:”)加上自己的进程ID。
观察程序执行时屏幕上出现的现象,并分析原因,进一步理解各个进程争夺临界资源(显示器)的情况。
接着在程序中使用系统调用locking( )来给每一个进程加锁,实现进程之间的互斥,试观察并分析出现的现象。
(2)进程的软中断通讯编制一段程序,实现进程的软中断通讯:使用系统调用fork( )创建两个子进程;再使用系统调用signal( )让父进程捕捉键盘上来的中断信号(即按Del键);在捕捉到中断信号后,父进程用系统调用kill( )向两个子进程发信号;子进程捕捉到信号后分别输出下列信息后终止:Child process1 is killed by parent!Child process2 is killed by parent!父进程等待两个子进程都终止以后,输出如下信息后终止:Parent process in killed!(3)进程的管道通讯编制一段程序,实现进程的管道通讯:使用系统调用pipe( )建立一条管道线;两个子进程分别循环向这条管道写一句话:Child 1 is sending a message!Child 2 is sending a message!而父进程则循环从管道中读出信息,显示在屏幕上。
进程通信实验报告进程通信实验报告概述进程通信是操作系统中非常重要的一个概念,它允许不同的进程之间进行数据的交换和共享。
在本次实验中,我们通过使用不同的进程通信机制,如管道、消息队列和共享内存,来实现进程之间的数据传输和通信。
本报告将详细介绍实验的背景、实验过程、结果分析以及对实验的总结。
实验背景进程通信是操作系统中的一个核心概念,它允许多个进程之间进行数据的交换和共享。
在现代操作系统中,进程通信是实现并发和协作的重要手段。
了解不同的进程通信机制以及它们的优缺点对于深入理解操作系统的原理和实现至关重要。
实验过程在本次实验中,我们使用了三种不同的进程通信机制:管道、消息队列和共享内存。
首先,我们创建了两个进程,一个作为发送方,一个作为接收方。
然后,我们分别使用了管道、消息队列和共享内存来实现进程之间的数据传输和通信。
管道是一种最简单的进程通信机制,它可以在父进程和子进程之间进行单向的通信。
我们通过创建一个管道,并将其连接到父进程和子进程的标准输入和标准输出,实现了父子进程之间的数据传输。
消息队列是一种更为灵活的进程通信机制,它可以实现多个进程之间的双向通信。
我们使用了系统提供的消息队列函数,创建了一个消息队列,并在发送方将消息发送到队列中,接收方则从队列中接收消息。
通过消息队列,我们实现了进程之间的异步通信。
共享内存是一种高效的进程通信机制,它允许多个进程共享同一块内存空间。
我们使用了共享内存函数,创建了一个共享内存区域,并将其映射到两个进程的虚拟地址空间中。
通过共享内存,我们实现了进程之间的数据共享和同步。
结果分析通过实验,我们发现不同的进程通信机制各有优缺点。
管道是最简单的一种机制,但只能实现单向通信,且只能用于具有亲缘关系的进程。
消息队列可以实现多个进程之间的双向通信,但消息的顺序可能会被打乱。
共享内存是最高效的一种机制,但需要额外的同步机制来保证数据的一致性。
总结进程通信是操作系统中非常重要的一个概念,它允许不同的进程之间进行数据的交换和共享。
实验六:Linux进程间通信(2)(4课时)实验目的:理解进程通信原理;掌握进程中信号量、共享内存、消息队列相关的函数的使用。
实验原理:Linux下进程通信相关函数除上次实验所用的几个还有:信号量信号量又称为信号灯,它是用来协调不同进程间的数据对象的,而最主要的应用是前一节的共享内存方式的进程间通信。
要调用的第一个函数是semget,用以获得一个信号量ID。
int semget(key_t key, int nsems, int flag);key是IPC结构的关键字,flag将来决定是创建新的信号量集合,还是引用一个现有的信号量集合。
nsems是该集合中的信号量数。
如果是创建新集合(一般在服务器中),则必须指定nsems;如果是引用一个现有的信号量集合(一般在客户机中)则将nsems指定为0。
semctl函数用来对信号量进行操作。
int semctl(int semid, int semnum, int cmd, union semun arg);不同的操作是通过cmd参数来实现的,在头文件sem.h中定义了7种不同的操作,实际编程时可以参照使用。
semop函数自动执行信号量集合上的操作数组。
int semop(int semid, struct sembuf semoparray[], size_t nops);semoparray是一个指针,它指向一个信号量操作数组。
nops规定该数组中操作的数量。
ftok原型如下:key_t ftok( char * fname, int id )fname就是指定的文件名(该文件必须是存在而且可以访问的),id是子序号,虽然为int,但是只有8个比特被使用(0-255)。
当成功执行的时候,一个key_t值将会被返回,否则-1 被返回。
共享内存共享内存是运行在同一台机器上的进程间通信最快的方式,因为数据不需要在不同的进程间复制。
通常由一个进程创建一块共享内存区,其余进程对这块内存区进行读写。
首先要用的函数是shmget,它获得一个共享存储标识符。
#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>int shmget(key_t key, int size, int flag);当共享内存创建后,其余进程可以调用shmat()将其连接到自身的地址空间中。
void *shmat(int shmid, void *addr, int flag);shmid为shmget函数返回的共享存储标识符,addr和flag参数决定了以什么方式来确定连接的地址,函数的返回值即是该进程数据段所连接的实际地址,进程可以对此进程进行读写操作。
断开共享内存连接:与shmat函数相反,shmdt是用来断开与共享内存附加点的地址,禁止本进程访问此片共享内存函数原型int shmdt(const void *shmaddr)函数传入值shmaddr:连接的共享内存的起始地址函数返回值成功:0出错:-1,错误原因存于error中附加说明本函数调用并不删除所指定的共享内存区,而只是将先前用shmat函数连接(attach)好的共享内存脱离(detach)目前的进程错误代码EINVAL:无效的参数shmaddr。
消息队列消息队列就是一个消息的链表。
可以把消息看作一个记录,具有特定的格式以及特定的优先级。
1.创建新消息队列或取得已存在消息队列原型:int msgget(key_t key, int msgflg);参数:key:键值,可以指定,也可以由函数ftok生成。
msgflg:IPC_CREAT值,若没有该队列,则创建一个并返回新标识符;若已存在,则返回原标识符。
IPC_EXCL值,若没有该队列,则返回-1;若已存在,则返回0。
2.向队列读/写消息原型:msgrcv从队列中取用消息:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);msgsnd将数据放到消息队列中:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); 参数:msqid:消息队列的标识码msgp:指向消息缓冲区的指针,此位置用来暂时存储发送和接收的消息msgsz:消息的大小。
msgtyp:从消息队列内读取的消息形态。
如果值为零,则表示消息队列中的所有消息都会被读取。
msgflg:用来指明核心程序在队列没有数据的情况下所应采取的行动。
3.设置消息队列属性原型:int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );参数:msgctl 系统调用对msgqid 标识的消息队列执行cmd 操作,系统定义了3 种cmd 操作:IPC_STAT , IPC_SET , IPC_RMIDIPC_STAT : 该命令用来获取消息队列对应的msqid_ds 数据结构,并将其保存到buf 指定的地址空间。
IPC_SET : 该命令用来设置消息队列的属性,要设置的属性存储在buf 中。
IPC_RMID : 从内核中删除msqid 标识的消息队列。
实验内容:1、完成教材上信号量实例,想一下ftok函数的作用?修改例子,创建2个进程完成原来父子进程对应的操作。
子进程代码:#include<sys/types.h>#include<unistd.h>#include<stdio.h>#include<stdlib.h>#include<sys/types.h>#include<sys/sem.h>#include<sys/ipc.h>#define DELAY_TIME 3union semun{int val;struct semid_ds *buf;unsigned short *array;};int init_sem(int sem_id,int init_value){union semun sem_union;sem_union.val = init_value;if(semctl(sem_id,0, SETVAL,sem_union)==-1){perror("Initialize semaphore");return -1;}return 0;}int del_sem(int sem_id){union semun sem_union;if(semctl(sem_id,0,IPC_RMID,sem_union)==-1) {perror("Delete semaphore");return -1;}}int sem_p(int sem_id){struct sembuf sem_b;sem_b.sem_num =0 ;sem_b.sem_op =-1;sem_b.sem_flg=SEM_UNDO;if(semop(sem_id,&sem_b,1)==-1){perror("P operation");return -1;}return 0;}int sem_v(int sem_id){struct sembuf sem_b;sem_b.sem_num =0 ;sem_b.sem_op =1;sem_b.sem_flg=SEM_UNDO;if(semop(sem_id,&sem_b,1)==-1){perror("V operation");return -1;}return 0;}int main(){pid_t result;int sem_id;sem_id =semget(ftok(".",'a'),1,0666|IPC_CREAT);init_sem(sem_id,0);printf("Child process will wait for some seconds...\n");sleep(DELAY_TIME);printf("The returned valud is %d in the child process(PID = %d)\n",result,getpid());sem_v(sem_id);}等待进程:#include<sys/types.h>#include<unistd.h>#include<stdio.h>#include<stdlib.h>#include<sys/types.h>#include<sys/sem.h>#include<sys/ipc.h>#define DELAY_TIME 3union semun{int val;struct semid_ds *buf;unsigned short *array;};int init_sem(int sem_id,int init_value){union semun sem_union;sem_union.val = init_value;if(semctl(sem_id,0, SETVAL,sem_union)==-1){perror("Initialize semaphore");return -1;}return 0;}int del_sem(int sem_id){union semun sem_union;if(semctl(sem_id,0,IPC_RMID,sem_union)==-1){perror("Delete semaphore");return -1;}}int sem_p(int sem_id){struct sembuf sem_b;sem_b.sem_num =0 ;sem_b.sem_op =-1;sem_b.sem_flg=SEM_UNDO;if(semop(sem_id,&sem_b,1)==-1){perror("P operation");return -1;}return 0;}int sem_v(int sem_id){struct sembuf sem_b;sem_b.sem_num =0 ;sem_b.sem_op =1;sem_b.sem_flg=SEM_UNDO;if(semop(sem_id,&sem_b,1)==-1){perror("V operation");return -1;}return 0;}int main(){pid_t result;int sem_id;sem_id =semget(ftok(".",'a'),1,0666|IPC_CREAT);init_sem(sem_id,0);sem_p(sem_id);printf("The returned value is %d in the father process (PID =%d)\n",result,getpid());sem_v(sem_id);del_sem(sem_id);}2、完成教材上共享内存实例,查看运行情况。