操作系统实验二:进程通信(管道及共享内存)

实验二:进程通信(一) ——管道及共享内存

一、实验目的

1、熟悉并掌握管道机制,并实现进程间通信
2、熟悉并掌握共享内存机制,并实现进程间通信

二、实验内容和步骤

1、任务一
(1)阅读以上父子进程利用管道进行通信的例子(例1),写出程序的运行结果并分析。
(2)编写程序:父进程利用管道将一字符串交给子进程处理。子进程读字符串,将里面的字符反向后再交给父进程,父进程最后读取并打印反向的字符串。
2、任务二
(1)阅读例2的程序,运行一次该程序,然后用ipcs命令查看系统中共享存储区的情况,再次执行该程序,再用ipcs命令查看系统中共享内存的情况,对两次的结果进行比较,并分析原因。最后用ipcrm命令删除自己建立的共享存储区。
(2)每个同学登陆两个窗口,先在一个窗口中运行例3程序1(或者只登陆一个窗口,先在该窗口中以后台方式运行程序1),然后在另一个窗口中运行例3程序2,观察程序的运行结果并分析。运行结束后可以用ctrl+c结束程序1的运行。
(3)编写程序:使用系统调用shmget(),shmat(),shmdt(),shmctl(),编制程序。要求在父进程中生成一个30字节长的私有共享内存段。接下来,设置一个指向共享内存段的字符指针,将一串大写字母写入到该指针指向的存贮区。调用fork()生成子进程,让子进程显示共享内存段中的内容。接着,将大写字母改成小写,子进程修改共享内存中的内容。之后,子进程将脱接共享内存段并退出。父进程在睡眠5秒后,在此显示共享内存段中的内容(此时已经是小写字母)。-

三、代码及运行结果分析

1、任务一

例1:

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include <sys/wait.h>
int main()
{
    
       int x,fd[2];
    char buf[30],s[30];
    pipe(fd);
    while ((x=fork())==-1);
    if (x==0)
    {
    
    
       close(fd[0]);
       printf("Child Process!\n");
       strcpy(buf,"This is an example\n");
       write(fd[1],buf,30);
       exit(0);
    }
    else{
    
    
       close(fd[1]);
       printf("Parent Process!\n");
       read(fd[0],s,30);
       printf("%s\n",s);
   }
   return 0;
}

(1)阅读以上父子进程利用管道进行通信的例子(例1),写出程序的运行结果并分析。
运行结果:
在这里插入图片描述

分析:
利用系统调用pipe()可创建一个简单的管道。fd[0]存放供读进程使用的文件描述符(管道出口),fd[1]存放供写程使用的文件描述符(管道入口)。首先运行父进程,然后关闭父进程,子进程开启,并向父进程发送消息,然后关闭子进程,父进程接收消息并打印输出。
(2)编写程序:父进程利用管道将一字符串交给子进程处理。子进程读字符串,将里面的字符反向后再交给父进程,父进程最后读取并打印反向的字符串。
编写程序如下:

#include<stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
    
    
        int x,count,left,right,temp,fd[2],fe[2];
        char c,buf[30],s[30];
        pipe(fd);
        pipe(fe);
        printf("please input a line of char:\n");
        scanf("%s",buf);
        while((x=fork())==-1);
        if(x==0){
    
    
                close(fd[0]);
                close(fe[1]);
                printf("Child Process!\n");
                write(fd[1],buf,30);
                read(fe[0],buf,30);
                printf("%s\n",buf);
                exit(0);
        }else{
    
    
                close(fd[1]);
                close(fe[0]);
                count=0;
                do{
    
    
                        read(fd[0],&c,1);
                        s[count++]=c;
                }while(c!='\0');
                printf("Parent Process!\n");
                printf("%s\n",s);count-=2;
                for(left=0,right=count;left<=count/2;left++,right--){
    
    
                        temp=s[left];
                        s[left]=s[right];
                        s[right]=temp;
                }
                write(fe[1],s,30);
                wait(0);
        }
}

运行结果:
在这里插入图片描述

分析:

调用pipe(fd);创建一个管道后,接着调用fork()函数产生两个进程,首先开始执行子进程,关闭管道出口,通过管道入口向管道中写入内容。父进程中,管道入口关闭,通过管道出口端从管道中读取之前写入内容,最后输出出来。

2、任务二

(1)阅读例2的程序,运行一次该程序,然后用ipcs命令查看系统中共享存储区的情况,再次执行该程序,再用ipcs命令查看系统中共享内存的情况,对两次的结果进行比较,并分析原因。最后用ipcrm命令删除自己建立的共享存储区。
例2:

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
    
    
	key_t key=15;
	int shmid_1,shmid_2;
	if ((shmid_1=shmget(key,1000,0644|IPC_CREAT))==-1){
    
    
        perror("shmget shmid_1");exit(1);
	}
	printf("First shared memory identifier is %d\n",shmid_1);
	if ((shmid_2=shmget(IPC_PRIVATE,20,0644))==-1){
    
    
        perror("shmget shmid_2");exit(2);
	}
	printf("Second shared memory identifier is %d\n",shmid_2);
	exit(0);
}

运行结果:
第一次运行该程序,然后用ipcs命令查看系统中共享存储区的情况,结果如下:

第二次运行该程序,然后用ipcs命令查看系统中共享存储区的情况,结果如下:
在这里插入图片描述

分析:
shmget()是建立一个新的共享区或返回一个已存在的共享存储区描述字;int shmgetkey_t key, int size, int shmflag),其中,key是用户指定的共享区号,size是共享存储区的长度,而shmflag用来标识共享内存段的创建条件机以及访问权限。若成功,则返回共享内存段的标识符,内核中用于唯一的标识一个对象。对存在于内核存储空间中的每个共享内存段,内核均为其维护着一个数据结构shmid_ds;若失败,则返回-1,设置errno。
在两次运行结束后的 第二个共享标识符是不一样的。所以在用ipcs查看时,共享内存段中的关键字,共享内存标识符,访问权限,字节等都是不一样的。

(2)每个同学登陆两个窗口,先在一个窗口中运行例3程序1(或者只登陆一个窗口,先在该窗口中以后台方式运行程序1),然后在另一个窗口中运行例3程序2,观察程序的运行结果并分析。运行结束后可以用ctrl+c结束程序1的运行。

例3(程序1)

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#define SHMKEY 75
#define K  1024
int shmid;
void cleanup()
{
    
    
shmctl(shmid,IPC_RMID,0);
exit(0);
 }

int main()
{
    
    
        int i, * pint;
        char* addr;
        for (i = 0; i < 20; i++) signal(i, cleanup);
        shmid = shmget(SHMKEY, 16 * K, 0777 | IPC_CREAT); /*建立16K共享区SHMKEY */
        addr = shmat(shmid, 0, 0);/*挂接,并得到共享区首地址 */
        printf("addr 0x%s\n", addr);
        pint = (int*)addr;
        for (i = 0; i < 256; i++) *pint++ = i;
        pause();/*等待接收进程读 */
}

例3(程序2)

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SHMKEY 75  
#define K  1024
int shmid;
int main (){
    
    
        int i,*pint;
        char *addr;
        shmid=shmget(SHMKEY,8*K,0777);/*取共享区SHMKEY的id */
        addr=(char *)shmat(shmid,0,0);/*连接共享区*/
        pint=(int *)addr;
        for (i=0;i<256;i++)
        printf("%d\n",*pint++);/*打印共享区中的内容*/
        return 0;
}

实验结果:
在这里插入图片描述

分析:
首先系统通过调用shmctl对预定义的shmid指向的内存段进行删除操作,然后系统调用shmget创建一个161024字节的共享内存段,成功返回共享内存段的标识符给shmid,之后系统再次调用shmat连接内存段,返回该共享内存段连接到调用进程地址空间上的地址addr。
程序1运行时,该程序开始执行,系统调用shmget创建一个8
1024字节的共享内存段,再通过调用shmat挂接内存段,由系统选择挂接地址,最终输出转换后的挂接地址。最后输出前255的内容。共享存储区机制只为通信进程提供了访问共享存储区的操作条件,而对通信的同步控制则要依靠信号量机制等才能完成。

(3)编写程序:使用系统调用shmget(),shmat(),shmdt(),shmctl(),编制程序。要求在父进程中生成一个30字节长的私有共享内存段。接下来,设置一个指向共享内存段的字符指针,将一串大写字母写入到该指针指向的存贮区。调用fork()生成子进程,让子进程显示共享内存段中的内容。接着,将大写字母改成小写,子进程修改共享内存中的内容。之后,子进程将脱接共享内存段并退出。父进程在睡眠5秒后,在此显示共享内存段中的内容(此时已经是小写字母)
编写程序如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SHMKEY 200
#define K 1024
int shmid_1,shmid_2;
int main ()
{
    
    
    int x,y,i,*pint;
    char *addr_1,*addr_2;
    char words[5]={
    
    'A','B','C','D','E'};
    shmid_1=shmget(SHMKEY,30*K,0777|IPC_CREAT); /*建立16K共享区SHMKEY */
    addr_1=shmat(shmid_1,0,0);/*挂接,并得到共享区首地址*/
    pint=(int *)addr_1;
    printf ("addr_1 0x%x\n",addr_1);
    for (i=0;i<5;i++) {
    
    
            *pint=words[i];
            pint++;
    }
    while((x=fork())==-1);
    if(x==0){
    
    
        shmid_2=shmget(SHMKEY,30*K,0777|IPC_CREAT); /*建立16K共享区SHMKEY */
        addr_2=shmat(shmid_2,0,0);/*挂接,并得到共享区首地址*/
        pint=(int *)addr_2;
        for(i=0;i<5;i++){
    
    
            printf("%c ",*pint);
            *pint=*pint+32;
            pint++;
    	}
        printf("\n");
        y=shmdt(addr_2);
        exit(0);
    }else{
    
    
        sleep(5);
        pint=(int *)addr_1;
        for(i=0;i<5;i++){
    
    
            printf("%c ",*pint);
            pint++;
        }
        printf("\n");
    }
    return 0; 
}

实验结果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/david2000999/article/details/122504414