计算机操作系统实验三 进程间的通信

2023-11-17

一、实验目的

1、了解什么是管道

2、熟悉UNIX/LINUX支持的管道通信方式

3、了解什么是消息

4、熟悉消息传送的机理

二、实验内容

1.编写程序实现进程的管道通信。用系统调用pipe( )建立一管道,二个子进程P1和P2分别向管道各写一句话:

    Child 1 is sending a message!

    Child 2 is sending a message!

父进程从管道中读出二个来自子进程的信息并显示。

2.消息的创建、发送和接收。使用系统调用msgget( ),msgsnd( ),msgrev( ),及msgctl( )编制一长度为1k的消息发送和接收的程序。

三、实验代码及注释

(一)进程的管道通信实验

1pipe( )

建立一无名管道。

系统调用格式

pipe(filedes)

参数定义

int  pipe(filedes);
int  filedes[2];

其中,filedes[1]是写入端,filedes[0]是读出端。

该函数使用头文件如下:

#include <unistd.h>
#inlcude <signal.h>
#include <stdio.h>

2read( )

系统调用格式

read(fd,buf,nbyte)

功能:从fd所指示的文件中读出nbyte个字节的数据,并将它们送至由指针buf所指示的缓冲区中。如该文件被加锁,等待,直到锁打开为止。

参数定义 

int  read(fd,buf,nbyte);
int  fd;
char *buf;
unsigned  nbyte;

3write( )

系统调用格式

write(fd,buf,nbyte)

功能:把nbyte 个字节的数据,从buf所指向的缓冲区写到由fd所指向的文件中。如文件加锁,暂停写入,直至开锁。

参数定义同read( )。

参考程序

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
int pid1,pid2;
main( )
    {
int fd[2];
char outpipe[100],inpipe[100];
pipe(fd);                       /*创建一个管道*/
while ((pid1=fork( ))= =-1);
if(pid1= =0)
  {
lockf(fd[1],1,0);
    sprintf(outpipe,"child 1 process is sending message!");
/*把串放入数组outpipe中*/
    write(fd[1],outpipe,50);     /*向管道写长为50字节的串*/
    sleep(5);                 /*自我阻塞5秒*/
    lockf(fd[1],0,0);
    exit(0);
            }
else
           {
while((pid2=fork( ))= =-1);
    if(pid2= =0)
{    lockf(fd[1],1,0);           /*互斥*/
   sprintf(outpipe,"child 2 process is sending message!");
                 write(fd[1],outpipe,50);
                 sleep(5);
           lockf(fd[1],0,0);
                 exit(0);
            }
               else
                {  wait(0);              /*同步*/
         read(fd[0],inpipe,50);   /*从管道中读长为50字节的串*/
                   printf("%s\n",inpipe);
         wait(0);
         read(fd[0],inpipe,50);
         printf("%s\n",inpipe);
                   exit(0);
               }
        }
}

(二)消息的发送与接收实验

1. msgget( )

获得一个消息的描述符,该描述符指定一个消息队列以便用于其他系统调用。如果希望创建一个新的消息队列,或者希望存取一个已经存在的消息队列,你可以使用系统调用msgget()。

该函数使用头文件如下:

#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>

(msgget()、msgsnd()、msgrcv ()、msgctl()所用头文件相同)

原型:int msgget (key-t key, int msgflag)

返回值:如果成功,返回消息队列标识符,如果失败,则返回-1

其中key是类似一个长整型,可由用户设定也可通过ftok()获得。msgflg的值是八进制的消息队列操作权和控制命令的组合。附:

操作允许权

八进制整数

用户可读

0400

用户可写

0200

同组可读

0040

同组可写

0020

其它可读

0004

其它可写

0002

操作权可相加而派生,如用户“可读”、“可写” 的 权 限 为0400|0200=0600。

控制命令可取IPC_CREAT或IPC_EXCL。IPC_CREAT如果内核中没有此队列,则创建它。IPC_EXCL当和IPC_CREAT一起使用时,如果队列已经存在,则失败。

如果单独使用IPC_CREAT,则msgget()要么返回一个新创建的消息队列的标识符,要么返回具有相同关键字值的队列的标识符。如果IPC_EXCL和IPC_CREAT一起使用,则msgget()要么创建一个新的消息队列,要么如果队列已经存在则返回一个失败值-1。IPC_EXCL单独使用是没有用处的。

如果要创建一个key=888且属主和同组可读写的消息队列,执行以下系统调用msgget(888,0660|IPC_CREAT)。下面看一个打开和创建一个消息队列的例子:

int open_queue(key_t keyval){
int qid;
if((qid=msgget(keyval,IPC_CREAT|0660))= =-1){
return(-1);
}
return(qid);
}

2. msgsnd()

发送一消息。向指定的消息队列发送一个消息,并将该消息链接到该消息队列的尾部。

系统调用格式:

msgsnd(msgqid,msgp,size,flag)

该函数使用头文件如下:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

参数定义:

int msgsnd(msgqid,msgp,size,flag)
int msgqid,size,flag;
struct msgbuf  * msgp;

其中msgqid是返回消息队列的描述符;msgp是指向用户消息缓冲区的一个结构体指针。缓冲区中包括消息类型和消息正文,即

{
    long  mtype;             /*消息类型*/
    char  mtext[ ];           /*消息的文本*/
 }

size指示由msgp指向的数据结构中字符数组的长度;即消息的长度。这个数组的最大值由MSG-MAX( )系统可调用参数来确定。flag规定当核心用尽内部缓冲空间时应执行的动作:进程是等待,还是立即返回。若在标志flag中未设置IPC_NOWAIT位,则当该消息队列中的字节数超过最大值时,或系统范围的消息数超过某一最大值时,调用msgsnd进程睡眠。若是设置IPC_NOWAIT,则在此情况下,msgsnd立即返回。

对于msgsnd( ),核心须完成以下工作:

(1)对消息队列的描述符和许可权及消息长度等进行检查。若合法才继续执行,否则返回;

(2)核心为消息分配消息数据区。将用户消息缓冲区中的消息正文,拷贝到消息数据区;

(3)分配消息首部,并将它链入消息队列的末尾。在消息首部中须填写消息类型、消息大小和指向消息数据区的指针等数据;

(4)修改消息队列头中的数据,如队列中的消息数、字节总数等。最后,唤醒等待消息的进程。

3. msgrcv( )

接受一消息。从指定的消息队列中接收指定类型的消息。

系统调用格式:

msgrcv(msgqid,msgp,size,type,flag)

本函数使用的头文件如下:   

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

参数定义:

int  msgrcv(msgqid,msgp,size,type,flag)
int  msgqid,size,flag;
struct  msgbuf  *msgp;
long  type;

其中,msgqid,msgp,size,flag与msgsnd中的对应参数相似,type是规定要读的消息类型,flag规定倘若该队列无消息,核心应做的操作。如此时设置了IPC_NOWAIT标志,则立即返回,若在flag中设置了MS_NOERROR,且所接收的消息大于size,则核心截断所接收的消息。

对于msgrcv系统调用,核心须完成下述工作:

(1)对消息队列的描述符和许可权等进行检查。若合法,就往下执行;否则返回;

(2)根据type的不同分成三种情况处理:

type=0,接收该队列的第一个消息,并将它返回给调用者;

type为正整数,接收类型type的第一个消息;

type为负整数,接收小于等于type绝对值的最低类型的第一个消息。

(3)当所返回消息大小等于或小于用户的请求时,核心便将消息正文拷贝到用户区,并从消息队列中删除此消息,然后唤醒睡眠的发送进程。但如果消息长度比用户要求的大时,则做出错返回。

4. msgctl( )

消息队列的操纵。读取消息队列的状态信息并进行修改,如查询消息队列描述符、修改它的许可权及删除该队列等。

系统调用格式:

msgctl(msgqid,cmd,buf);

本函数使用的头文件如下:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

参数定义:    

int msgctl(msgqid,cmd,buf);
int  msgqid,cmd;
struct  msgqid_ds  *buf;

其中,函数调用成功时返回0,不成功则返回-1。buf是用户缓冲区地址,供用户存放控制参数和查询结果;cmd是规定的命令。命令可分三类:

(1)IPC_STAT。查询有关消息队列情况的命令。如查询队列中的消息数目、队列中的最大字节数、最后一个发送消息的进程标识符、发送时间等;

(2)IPC_SET。按buf指向的结构中的值,设置和改变有关消息队列属性的命令。如改变消息队列的用户标识符、消息队列的许可权等;

(3)IPC_RMID。消除消息队列的标识符。

msgqid_ds  结构定义如下:

struct  msgqid_ds
   {  struct  ipc_perm  msg_perm;     /*许可权结构*/
      short  pad1[7];                 /*由系统使用*/
      ushort msg_qnum;                /*队列上消息数*/
      ushort msg_qbytes;              /*队列上最大字节数*/
      ushort msg_lspid;               /*最后发送消息的PID*/
      ushort msg_lrpid;               /*最后接收消息的PID*/
      time_t msg_stime;               /*最后发送消息的时间*/
      time_t msg_rtime;               /*最后接收消息的时间*/
      time_t msg_ctime;               /*最后更改时间*/
     };
struct  ipc_perm
   {  ushort uid;                     /*当前用户*/
      ushort gid;                     /*当前进程组*/
      ushort cuid;                    /*创建用户*/
      ushort cgid;                    /*创建进程组*/
      ushort mode;                    /*存取许可权*/
      { short pid1; long pad2;}       /*由系统使用*/ 
    }

参考程序

1、client.c

#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#define MSGKEY 75
struct  msgform
  {  long  mtype;
     char  mtext[1000];
}msg;
int  msgqid;
void client()
{
      int i;
msgqid=msgget(MSGKEY,0777);   /*打开75#消息队列*/
for(i=10;i>=1;i--)
{
  msg.mtype=i;
printf(“(client)sent\n”);
msgsnd(msgqid,&msg,1024,0);     /*发送消息*/
}
exit(0);
}
main( )
{
  client( );
}

2、server.c

#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#define MSGKEY 75
struct  msgform
  {  long  mtype;
     char  mtext[1000];
}msg;
int  msgqid;
void server( )
{
        msgqid=msgget(MSGKEY,0777|IPC_CREAT);  /*创建75#消息队列*/
do
          {
msgrcv(msgqid,&msg,1030,0,0);   /*接收消息*/
    printf(“(server)received\n”);
}while(msg.mtype!=1);
msgctl(msgqid,IPC_RMID,0);  /*删除消息队列,归还资源*/
exit(0);
}
main( )
{ 
server( );
}

四、运行结果截图

五、调试和运行程序过程中产生的问题及采取的措施

问题:文件名创建不正确,路径使用错误。

措施:请教老师,在同学的讨论下完成。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

计算机操作系统实验三 进程间的通信 的相关文章

随机推荐

  • 浅谈Hadoop体系和MPP体系

    浅谈Hadoop体系和MPP体系 引言 如题 在大数据发展至今 为了应对日益繁多的数据分析处理 和解决客户各种奇思妙 怪 想需求 形形色色的大数据处理的框架和对应的数据存储手段层出不穷 有老当益壮的Hadoop体系 依靠Hadoop巨大的社
  • 基于STM32和EV1527的无线接收解码程序

    一 1527的数据帧结构 无线遥控的编码 从编码类型上来说 分为2类 一类是固定码 也就是编码芯片的地址是不变的 芯片型号以 EV1527 PT2262 为代表 另一种是滚动码 芯片的地址码是变化的 芯片以HS300 HS301为代表 1
  • 数据结构顺序栈C++实现

    栈 先入后出 根据存储方式可以分为顺序栈和链式栈 顺序栈的存储基于数组 链式栈的存储基于链表 关于链表的实现可以参考上一篇博客 https blog csdn net Brillian123 article details 12354964
  • 模糊控制理论基础

    模糊控制理论基础 模糊控制的定义 模糊控制器的输出是通过观察过程的状态和一些如何 控制过程的规则的推理得到的 它包括测量信息的模糊化 推理机制 输出模糊集的精确化 1 模糊集合 普通集合 具有某种特定属性的对象的全体 确定性 模糊集合 隶属
  • 机器视觉运动控制一体机应用例程(十一)产品全局外观检测

    前面讲述的外观检测的课程中 我们都是以矩形ROI区域框选我们需要检测的外观表面范围 但是很多产品外形通常都不是规则的矩形或者圆形 用矩形或者圆形ROI区域很难对产品的外观进行全局检测 可能会遗漏掉某些细节部分 因此 我们引入了将提取的产品轮
  • 全景解密量子信息技术:高层集中学习,国家战略,三大领域一文看懂

    来源 智东西 内参来源 中国信通院 IPRdaily中文网 10月16日下午 高层就量子科技研究相关前景举行了一次会议 强调当今世界正经历百年未有之大变局 科技创新是其中一个关键变量 要充分认识推动量子科技发展的重要性 加强量子科技发展战略
  • numpy之索引和切片

    索引和切片 一维数组 一维数组很简单 基本和列表一致 它们的区别在于数组切片是原始数组视图 这就意味着 如果做任何修改 原始都会跟着更改 这也意味着 如果不想更改原始数组 我们需要进行显式的复制 从而得到它的副本 copy import n
  • json转xml、xml转json

    一 jar包 所需jar包 二 xml2json 方法一 使用json lib 代码 public String xml2json String xml 创建XMLSerializer对象 XMLSerializer xmlSerializ
  • 计算机房面积标准,机房建设标准与规范[共14页].pdf

    电子信息系统机房设计规范 施行日期 2009 年 6 月 1 日 1 总则 1 0 1 为规范电子信息系统机房设计 确保电子信息系统安全 稳定 可靠地运行 做到技术先进 经 济合理 安全适用 节能环保 制定本规范 1 0 2 本规范适用于建
  • GPU工作原理与理解

    本周看GPU看得有点儿乱 GPU英文全称Graphic Processing Unit 中文翻译为 图形处理器 由于GPU具有高并行结构 highly parallel structure 所以GPU在处理图形数据和复杂算法方面拥有比CPU
  • linux并行计算环境搭建与使用,Windows和Linux系统下并行计算环境MPI和OpenMP的搭建...

    windows平台下在Visual Studio2019配置MPI环境 MPI下载安装 项目配置 右击项目 gt 属性 进行配置 右上角 gt 配置管理器 gt 活动解决方案平台 选择 x64 VC 目录 gt 包含目录 添加 C Prog
  • CUDA 矩阵乘法优化

    矩阵乘法 为了单纯起见 我们这里以方形的矩阵为例子 基本上 假设有两个矩阵 A 和 B 则计算 AB C 的方法如下 for j 0 j lt n j C i j 0 for k 0 k lt n k C i j A i k B k j 一
  • python安装包国内镜像,pip使用国内镜像

    目录 python 安装包镜像 pip下载时使用国内镜像 python 安装包镜像 下载python安装包和pip下载第三方库时 由于一些客观原因 下载外网文件速度很慢 这时可以使用淘宝镜像下载 http npm taobao org mi
  • Qt *.pro文件的INCLUDEPATH和LIBS写法

    Qt pro文件的INCLUDEPATH和LIBS写法 一般的通用 如图所示 INCLUDEPATH usr local qwt 6 1 3 include INCLUDEPATH include LIBS L usr local qwt
  • 基于nginx的tomcat负载均衡和集群(超简单)

    今天看到 基于apache的tomcat负载均衡和集群配置 这篇文章成为javaEye热点 略看了一下 感觉太复杂 要配置的东西太多 因此在这里写出一种更简洁的方法 要集群tomcat主要是解决SESSION共享的问题 因此我利用memca
  • OpenCV的使用——读取、写入和显示图像

    代码 import the cv2 library import cv2 The function cv2 imread is used to read an image Read an image img color cv2 imread
  • Java JDBC连接数据库 查询SELECT

    package com edu import java sql public class jdbctest public static void main String args throws SQLException ClassNotFo
  • ubuntu 查看显卡命令

    要查看 Ubuntu 系统中的显卡信息 可以使用如下命令 lspci grep VGA 这条命令可以列出系统中所有的显卡设备 lshw c video 这条命令可以列出系统中的所有显卡信息 包括型号 芯片厂商和其他详细信息 glxinfo
  • Android颜色透明度(不透明度)对应的十六进制

    颜色值 AARRGGBB 透明度百分比和十六进制对应关系 下面是透明度 再加上平常写得颜色值就表示该颜色值多少透明度了 一 一张表格 基本都概括 方便查找和使用 透明度 十六进制 100 FF 99 FC 98 FA 97 F7 96 F5
  • 计算机操作系统实验三 进程间的通信

    一 实验目的 1 了解什么是管道 2 熟悉UNIX LINUX支持的管道通信方式 3 了解什么是消息 4 熟悉消息传送的机理 二 实验内容 1 编写程序实现进程的管道通信 用系统调用pipe 建立一管道 二个子进程P1和P2分别向管道各写一