资源描述
精品文档
实验五:进程间通信
l 实验目的:
学会进程间通信方式:无名管道,有名管道,信号,共享内存
l 实验要求:
(一)在父进程中创建一无名管道,并创建子进程来读该管道,父进程来写该管道
(二)在进程中为SIGBUS注册处理函数,并向该进程发送SIGBUS信号
(三)创建一共享内存,实现放进程间通信
l 实验器材:
软件:安装了Linux的vmware虚拟机
硬件:PC机一台
l 实验步骤:
(一)无名管道的使用
1、编写实验代码pipe_rw.c
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int pipe_fd[2];
pid_t pid;
char buf_r[100];
char* p_wbuf;
int r_num;
memset(buf_r,0,sizeof(buf_r));
/*创建管道*/
if(pipe(pipe_fd)<0)
{
printf("pipe create error\n");
return -1;
}
/*创建子进程*/
if((pid=fork())==0) //子进程执行代码
{
//1、子进程先关闭了管道的写端
//2、让父进程先运行,这样父进程先写子进程才有内容读
//3、读取管道的读端,并输出数据
//4、关闭管道的读端,并退出
}
else if(pid>0) //父进程执行代码
{
//1、父进程先关闭了管道的读端
//2、向管道写入字符串数据
//3、关闭写端,并等待子进程结束后退出
}
return 0;
}
2、编译应用程序pipe_rw.c
3、运行应用程序
子进程先睡两秒让父进程先运行,父进程分两次写入“hello”和“pipe”,然后阻塞等待子进程退出,子进程醒来后读出管道里的内容并打印到屏幕上再退出,父进程捕获到子进程退出后也退出
4、由于fork函数让子进程完整地拷贝了父进程的整个地址空间,所以父子进程都有管道的读端和写端。我们往往希望父子进程中的一个进程写一个进程读,那么写的进程最后关掉读端,读的进程最好关闭掉写端
(二)信号处理
1、编写实验代码sig_bus.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
//1、自定义信号处理函数,处理SIGBUS信号,打印捕捉到信号即可
int main()
{
printf("Waiting for signal SIGBUS \n ");
//2、注册信号处理函数
pause();//将进程挂起直到捕捉到信号为止
exit(0);
}
用signal系统调用为SIGBUS信号注册信号处理函数my_func,然后将进程挂起等待SIGBUS信号。所以需要向该进程发送SIGBUS信号才会执行自定义的信号处理函数
2、编译应用程序sig_bus.c
3、运行应用程序
先先一个终端中运行sig_bus,会看到进程挂起,等待信号
然后在另一个终端中,查找到运行sig_bus这个产生的进程号,用kill命令发送SIGBUS信号给这个进程
我们可以看到前面挂起的进程在接收到这个信号后的处理
用自定义信号处理函数my_func来处理,所以打印了I have get SIGBUS这样一句话
(三) 共享内存
1、 本实验利用共享内存完成两个进程之间的通信,发送端的消息类型设置为该进程的进程号(可以取其他值),接收端接收消息(类似消息队列的功能),这里同时需要采用信号量为同步机制完善两个进程间的通信。
2、 下面是共享内存缓冲区的数据结构的定义
/* shm_com.h */
#ifndef SHM_COM_H
#define SHM_COM_H
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SHM_BUFF_SZ 2048
struct shm_buff
{
int pid;
char buffer[SHM_BUFF_SZ];
};
#endif /* SHM_COM_H */
以下是发送端的部分程序,请完善信号量的操作代码
/* producer.c */
#include "shm_com.h"
#include <signal.h>
int ignore_signal(void)
{
signal(SIGINT, SIG_IGN);
signal(SIGSTOP, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
return 0;
}
int main()
{
void *shared_memory = NULL;
struct shm_buff *shm_buff_inst;
char buffer[BUFSIZ];
int shmid, semid;
ignore_signal(); /* 防止程序非正常退出 */
/* 创建一个信号量*/
/* 初始值为1 */
/* 创建共享内存 */
shmid = shmget(ftok(".", 'b'), sizeof(struct shm_buff), 0666|IPC_CREAT);
if (shmid == -1)
{
perror("shmget failed");
//删除信号量
exit(1);
}
/* 将共享内存地址映射到当前进程地址空间 */
shared_memory = shmat(shmid, (void*)0, 0);
if (shared_memory == (void*)-1)
{
perror("shmat");
//删除信号量
exit(1);
}
printf("Memory attached at %X\n", (int)shared_memory);
/* 获得共享内存的映射地址 */
shm_buff_inst = (struct shm_buff *)shared_memory;
do
{
printf("Enter some text to the shared memory(enter 'quit' to exit):");
/* 向共享内存写入数据 */
if (fgets(shm_buff_inst->buffer, SHM_BUFF_SZ, stdin) == NULL)
{
perror("fgets");
sem_v(semid);
break;
}
shm_buff_inst->pid = getpid();
} while(strncmp(shm_buff_inst->buffer, "quit", 4) != 0);
/* 删除信号量 */
/* 删除共享内存到当前进程地址空间中的映射 */
if (shmdt(shared_memory) == 1)
{
perror("shmdt");
exit(1);
}
exit(0);
}
以下是接收端程序部分,请完善信号量操作的代码
/* customer.c */
#include "shm_com.h"
int main()
{
void *shared_memory = NULL;
struct shm_buff *shm_buff_inst;
int shmid, semid;
/* 获得信号量 */
/* 获得共享内存 */
shmid = shmget(ftok(".", 'b'), sizeof(struct shm_buff), 0666|IPC_CREAT);
if (shmid == -1)
{
perror("shmget");
exit(1);
}
/* 将共享内存地址映射到当前进程地址空间 */
shared_memory = shmat(shmid, (void*)0, 0);
if (shared_memory == (void*)-1)
{
perror("shmat");
exit(1);
}
printf("Memory attached at %X\n", (int)shared_memory);
/* 获得共享内存的映射地址 */
shm_buff_inst = (struct shm_buff *)shared_memory;
do
{
printf("Shared memory was written by process %d :%s", shm_buff_inst->pid, shm_buff_inst->buffer);
if (strncmp(shm_buff_inst->buffer, "quit", 4) == 0)
{
break;
}
shm_buff_inst->pid = 0;
memset(shm_buff_inst->buffer, 0, SHM_BUFF_SZ);
} while(1);
/* 删除共享内存到当前进程地址空间中的映射 */
if (shmdt(shared_memory) == -1)
{
perror("shmdt");
exit(1);
}
/* 删除共享内存 */
if (shmctl(shmid, IPC_RMID, NULL) == -1)
{
perror("shmctl(IPC_RMID)");
exit(1);
}
exit(0);
}
3、 实验结果
l 上机报告要求:
1、总结pipe(),signal(),shmget()函数定义原型,返回值和参数的意义
2、利用有名管道FIFO实现类似第一个实验的功能,一个程序fifo_read.c写数据”Hi Linux”,另一个程序fifo_write.c读数据并打印出来。
精品文档
展开阅读全文