当前位置:文档之家› Linux进程间通信(2)实验报告

Linux进程间通信(2)实验报告

实验六: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、完成教材上共享内存实例,查看运行情况。

相关主题