——管道及共享内存
学号: 姓名: 班级:
一、 实验目的
(1)加深对管道概念的理解。
(2)掌握利用管道进行进程通信的程序设计。
(3) Linux系统的共享内存机制允许在任意进程间大批量地交换数据。本实验的目的是了解和熟悉Linux支持的共享存储区机制。
二、 实验内容
任务一、 管道 (1)运行源码
运行上文进程管理中给出的例子,查看自己运行的结果,并进行分析。 (2)编写程序
父进程将一字符串交给子进程处理。子进程读字符串,将里面的字符反向后再交给父进程,父进程最后打印反向的字符串。 任务二、 共享内存
(1)阅读例2的程序,运行一次该程序,然后用ipcs命令查看系统中共享存储区的情况,再次执行该程序,再用ipcs命令查看系统中共享内存的情况,对两次的结果进行比较,并分析原因。最后用ipcrm命令删除自己建立的共享存储区。 (有关ipcs和ipcrm介绍见后面一页) (2)每个同学登陆两个窗口,先在一个窗口中运行例3程序1(或者只登陆一个窗口,先在该窗口中以后台方式运行程序1),然后在另一个窗口中运行例3程序2,观察程序的运行结果并分析。运行结束后可以用ctrl+c结束程序1的运行。
(3)编写程序:使用系统调用shmget(),shmat(),shmdt(),shmctl(),编制程序。要求在父进程中生成一个30字节长的私有共享内存段。接下来,设置一个指向共享内存段的字符指针,将一串大写字母写入到该指针指向的存贮区。调用fork()生成子进程,让子进程显示共享内存段中的内容。接着,将大写字母改成小写,子进程修改共享内存中的内容。之后,子进程将脱接共享内存段并退出。父进程在睡眠5秒后,在此显示共享内存段中的内容(此时已经是小写字母)。
三、 源代码
任务一、管道 (1) 运行源码 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\ } }
实验结果:
(2) 编写程序 #include 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:\"); scanf(\"%s\ 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\ 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\ 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); } } 任务二、 (1)运行程序 用ipcs命令查看系统中共享存储区的情况 再次运行程序 再用ipcs命令查看系统中共享内存的情况: 用ipcrm命令删除自己建立的共享存储区 分析 shmget() 是建立一个新的共享区或返回一个已存在的共享存储区描述字; int shmget(key_t key,int size,int shmflag),其中,key是用户指定的共享区号,size是共享存储区的长度,而shmflag用来标识共享内存段的创建条件机以及访问权限。 成功,返回共享内存段的标识符,内核中用于唯一的标识一个对象。对存在于内核存贮空间中的每个共享内存段,内核均为其维护着一个数据结构shmid_ds。 失败,返回-1,设置errno。 ①第一个参数key(键值),预定义的数据类型key_t,其类型是长整型。用来创建IPC标识符,shmget()返回的标识符与key值一一对应,不同的key值返回不同的标识符。 ②第二个参数size,决定了共享内存段的大小(若访问已存在的内存段,该参数可设为0)。有最大字节数的限制,0x2000000=32M,极限值,可查看/usr/include/linux/shm.h。 ③第三个参数shmflag,用于设置访问权限及标识创建条件。 在/usr/include/linux/ipc.h中可找到一些预定义的常量: #define IPC_PRIVATE ((key_t)0) #define IPC_CREAT 00001000(八进制) #define IPC_EXCL 00002000(八进制) key值为IPC_PRIVATE时,调用shmget将生成一个新的共享内存段。 Shmflag为0666|IPC_CREAT时,如果key值是新的,返回新创建的内存段标识符。 若key值是旧的,返回已存在内核中的具有相同关键字值的内存段标识符。 对两次的结果进行比较:第一次运行完程序时,First shared memory identifier is 2228261 Second shared memory identifier is 2261030 第二次运行完程序时:First shared memory identifier is 2228261 Second shared memory identifier is 2293799 所以两次运行结束后的 第二个共享标识符是不一样的。在用ipcs查看时,共享内存段中的关键字,共享内存标识符,访问权限,字节等都是不一样的。 (2)在另一个窗口中运行例三程序2 程序一后台运行 程序输出从0到255 的数 在程序2中,另一个进程附接到与关键字SHMKEY相关联的存储区上。也就是与程序1所述的同一个存储区上.为了表明每个进程可以附接一个共享存储区的不同总量,程序2中只取该存储区的8K字节.该进程等待着直到程序1中进程在共享存储区中的第一个字节写入一个非零值后读出该存储区,此时程序1的进程暂停以使程序2的进程执行读出打印操作. 需要指出的是,共享存储区机制只为通信进程提供了访问共享存储区的操作条件,而对通信的同步控制则要依靠信号量机制等才能完成。 (3)编写程序:使用系统调用shmget(),shmat(),shmdt(),shmctl(),编制程序 #include #define SHMKEY 324 /*在实际实验过程中,为了避免每个同学建立的共享存储区关键字一样而相互干扰,关键字请用学号末3位*/ #define K 1024 int shmid; main() { int i; char *pint; char *addr; extern char * shmat (); extern cleanup (); 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%x\\n\pint=(char *)addr; for (i='a';i<='e';i++) *pint++=i; pause();/*等待接收进程读 */ } cleanup() { shmctl(shmid,IPC_RMID,0); exit (); } #include #define SHMKEY 324 /*在实际实验过程中,为了避免每个同学建立的共享存储区关键字一样而相互干扰,关键字请用学号末3位*/ #define K 1024 int shmid; main () { int i; char *pint; char *addr; extern char * shmat (); shmid=shmget(SHMKEY,8*K,0777);/*取共享区SHMKEY的id */ addr=shmat(shmid,0,0);/*连接共享区*/ pint=(char *)addr; for (i=0;i<5;i++) printf(\"%c\\n\打印共享区中的内容*/ } 实验结果 实验心得: 通过本次实验自己收获了很多,了解了管道进程间通信形式,管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道。数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。另外,对于共享内存也有一定的了解。多个进程可通过对共享存贮区中的数据进行读和写来实现通信。总之,本次实验自己收获了很多。 因篇幅问题不能全部显示,请点此查看更多更全内容