Linux系统编程实验六进程间通信.docx
- 文档编号:7953309
- 上传时间:2023-01-27
- 格式:DOCX
- 页数:13
- 大小:149.49KB
Linux系统编程实验六进程间通信.docx
《Linux系统编程实验六进程间通信.docx》由会员分享,可在线阅读,更多相关《Linux系统编程实验六进程间通信.docx(13页珍藏版)》请在冰豆网上搜索。
Linux系统编程实验六进程间通信
实验六:
进程间通信
●实验目的:
学会进程间通信方式:
无名管道,有名管道,信号,消息队列,
●实验要求:
(一)在父进程中创建一无名管道,并创建子进程来读该管道,父进程来写该管道
(二)在进程中为SIGBUS注册处理函数,并向该进程发送SIGBUS信号
(三)创建一消息队列,实现向队列中存放数据与读取数据
●实验器材:
软件:
安装了Linux的vmware虚拟机
硬件:
PC机一台
●实验步骤:
(一)无名管道的使用
1、编写实验代码pipe_rw、c
#include
#include
#include
#include
#include
#include
intmain()
{
intpipe_fd[2];//管道返回读写文件描述符
pid_tpid;
charbuf_r[100];
char*p_wbuf;
intr_num;
memset(buf_r,0,sizeof(buf_r));//将buf_r初始化
charstr1[]=”parentwrite1“holle””;
charstr2[]=”parentwrite2“pipe”\n”;
r_num=30;
/*创建管道*/
if(pipe(pipe_fd)<0)
{
printf("pipecreateerror\n");
return-1;
}
/*创建子进程*/
if((pid=fork())==0)//子进程执行代码
{
//1、子进程先关闭了管道的写端
close(pipe_fd[1]);
//2、让父进程先运行,这样父进程先写子进程才有内容读
sleep
(2);
//3、读取管道的读端,并输出数据
if(read(pipe_fd[0],buf_r,r_num)<0)
{
printf(“readerror!
”);
exit(-1);
}
printf(“%s\n”,buf_r);
//4、关闭管道的读端,并退出
close(pipe_fd[1]);
}
elseif(pid>0)//父进程执行代码
{
//1、父进程先关闭了管道的读端
close(pipe_fd[0]);
//2、向管道写入字符串数据
p_wbuf=&str1;
write(pipe_fd[1],p_wbuf,sizof(p_wbuf));
p_wbuf=&str2;
write(pipe_fd[1],p_wbuf,sizof(p_wbuf));
//3、关闭写端,并等待子进程结束后退出
close(pipe_fd[1]);
}
return0;
}
/***********************
#include
#include
#include
#include
#include
#include
intmain()
{
intpipe_fd[2];//管道返回读写文件描述符
pid_tpid;
charbuf_r[100];
char*p_wbuf;
intr_num;
memset(buf_r,0,sizeof(buf_r));//将buf_r初始化
charstr1[]="holle";
charstr2[]="pipe";
r_num=10;
/*创建管道*/
if(pipe(pipe_fd)<0)
{
printf("pipecreateerror\n");
return-1;
}
/*创建子进程*/
if((pid=fork())==0)//子进程执行代码
{
close(pipe_fd[1]);//1、子进程先关闭了管道的写端
//2、让父进程先运行,这样父进程先写子进程才有内容读
//3、读取管道的读端,并输出数据
if(read(pipe_fd[0],buf_r,r_num)<0)
{
printf("read1error!
");
exit(-1);
}
printf("\nparentwrite1%s!
",buf_r);
sleep
(1);
if(read(pipe_fd[0],buf_r,r_num)<0)
{
printf("read2error!
");
exit(-1);
}
printf("\nparentwrite2%s!
",buf_r);
close(pipe_fd[1]);//4、关闭管道的读端,并退出
exit
(1);
//printf("childerror!
");
}
elseif(pid>0)//父进程执行代码
{
close(pipe_fd[0]);//1、父进程先关闭了管道的读端
p_wbuf=str1;//2、向管道写入字符串数据
write(pipe_fd[1],p_wbuf,sizeof(str1));
sleep
(1);
p_wbuf=str2;
write(pipe_fd[1],p_wbuf,sizeof(str2));
close(pipe_fd[1]);//3、关闭写端,并等待子进程结束后退出
exit
(1);
//printf("fathererror!
");
}
return0;
}
**************************/
2、编译应用程序pipe_rw、c
3、运行应用程序
子进程先睡两秒让父进程先运行,父进程分两次写入“hello”与“pipe”,然后阻塞等待子进程退出,子进程醒来后读出管道里的内容并打印到屏幕上再退出,父进程捕获到子进程退出后也退出
4、由于fork函数让子进程完整地拷贝了父进程的整个地址空间,所以父子进程都有管道的读端与写端。
我们往往希望父子进程中的一个进程写一个进程读,那么写的进程最后关掉读端,读的进程最好关闭掉写端
(二)信号处理
1、编写实验代码sig_bus、c
#include
#include
#include
//1、自定义信号处理函数,处理SIGBUS信号,打印捕捉到信号即可
staticvoidsignal_handler(intsigno)
{
if(signo==SIGBUS)
printf(“\nIhavegetSIGBUS”);
exit(EXIT_FAILURE);
}
intmain()
{
printf("WaitingforsignalSIGBUS\n");
//2、注册信号处理函数
if(signal(SIGBUS,signal_handler)==SIG_ERR)
{
fprintf(stderr,”cannothandleSIGBUS\n”);
exit(EXIT_FAILURE);
}
pause();//将进程挂起直到捕捉到信号为止
exit(0);
return0;
}
/********************************
#include
#include
#include
#include
//1、自定义信号处理函数,处理SIGBUS信号,打印捕捉到信号即可
staticvoidsignal_handler(intsigno)
{
if(signo==SIGBUS)
printf("IhavegetSIGBUS");
exit(EXIT_FAILURE);
}
intmain()
{
printf("WaitingforsignalSIGBUS\n");
//2、注册信号处理函数
if(signal(SIGBUS,signal_handler)==SIG_ERR)
{
fprintf(stderr,"cannothandleSIGBUS\n");
exit(EXIT_FAILURE);
}
pause();//将进程挂起直到捕捉到信号为止
exit(0);
return0;
}
***************************/
用signal系统调用为SIGBUS信号注册信号处理函数my_func,然后将进程挂起等待SIGBUS信号。
所以需要向该进程发送SIGBUS信号才会执行自定义的信号处理函数
2、编译应用程序sig_bus、c
3、运行应用程序
先先一个终端中运行sig_bus,会瞧到进程挂起,等待信号
然后在另一个终端中,查找到运行sig_bus这个产生的进程号,用kill命令发送SIGBUS信号给这个进程
我们可以瞧到前面挂起的进程在接收到这个信号后的处理
用自定义信号处理函数my_func来处理,所以打印了IhavegetSIGBUS这样一句话
●上机报告要求:
1、总结pipe(),signal()的函数定义原型,返回值与参数的意义
表头文件:
#include
定义函数:
intpipe(int[2]);
函数说明(参数):
pipe()会建立管道,并将文件描述词由参数数组返回。
[0]为管道里的读取端,[1]则为管道的写入端。
返回值:
若成功则返回零,否则返回-1,错误原因存于errno中。
阻塞问题:
当管道中的数据被读取后,管道为空。
一个随后的read()调用将默认的被阻塞,等待某些数据写入。
功能:
管道就是一种把两个进程之间的标准输入与标准输出连接起来的机制,从而提供一种让多个进程间通信的方法,当进程创建管道时,每次都需要提供两个文件描述符来操作管道。
其中一个对管道进行写操作,另一个对管道进行读操作。
对管道的读写与一般的IO系统函数一致,使用write()函数写入数据,使用read()读出数据。
表头文件:
#include
功能:
设置某一信号的对应动作
函数原型 :
void(*signal(intsignum,void(*handler)(int)))(int);
或者:
typedefvoid(*sig_t)(int); sig_tsignal(intsignum,sig_thandler);
可瞧成就是signal()函数(它自己就是带有两个参数,一个为整型,一个为函数指针的函数),而这个signal()函数的返回值也为一个函数指针,这个函数指针指向一个带整型参数,并且返回值为void的一个函数。
参数说明:
第一个参数signum指明了所要处理的信号类型,它可以取除了SIGKILL与SIGSTOP外的任何一种信号。
第二个参数handler描述了与信号关联的动作,它可以取以下三种值:
(1)一个返回值为正数的函数地址
此函数必须在signal()被调用前申明,handler中为这个函数的名字。
当接收到一个类型为sig的信号时,就执行handler所指定的函数。
这个函数应有如下形式的定义:
intfunc(intsig); sig就是传递给它的唯一参数。
执行了signal()调用后,进程只要接收到类型为sig的信号,不管其正在执行程序的哪一部分,就立即执行func()函数。
当func()函数执行结束后,控制权返回进程被中断的那一点继续执行。
(2)SIGIGN
这个符号表示忽略该信号,执行了相应的signal()调用后,进程会忽略类型为sig的信号。
(3)SIGDFL
这个符号表示恢复系统对信号的默认处理。
函数说明 :
signal()会依参数signum指定的信号编号来设置该信号的处理函数。
当指定的信号到达时就会跳转到参数handler指定的函数执行。
当一个信号的信号处理函数执行时, 如果进程又接收到了该信号,该信号会自动被储存而不会中断信号处理函数的执行,直到信号处理函数执行完毕再重新调用相应的处理函数。
但就是如果在信号处理函数执行时进程收到了其它类型的信号,该函数的执行就会被中断。
返回值:
返回先前的信号处理函数指针,如果有错误则返回SIG_ERR(-1)。
附加说明 :
在信号发生跳转到自定的handler处理函数执行后,系统会自动将此处理函数换回原来系统预设的处理方式,如果要改变此操作请改用sigaction()。
下面的情况可以产生Signal:
1、按下CTRL+C产生SIGINT
2、硬件中断,如除0,非法内存访问(SIGSEV)等等
3、Kill函数可以对进程发送Signal
4、Kill命令。
实际上就是对Kill函数的一个包装
5、 软件中断。
如当AlarmClock超时(SIGURG),当Reader中止之后又向管道写数据(SIGPIPE),等等
命名管道FIFO
功能:
管道最大的劣势就就是没有名字,只能用于有一个共同祖先进程的各个进程之间。
FIFO代表先进先出,单它就是一个单向数据流,也就就是半双工,与管道不同的就是:
每个FIFO都有一个路径与之关联,从而允许无亲缘关系的进程访问。
头文件:
#include
#include
函数定义原型:
intmkfifo(constchar*pathname,mode_tmode);
参数:
这里pathname就是路径名,mode就是sys/stat、h里面定义的创建文件的权限、
2、利用有名管道FIFO实现类似第一个实验的功能,一个程序fifo_read、c写数据”HiLinux”,另一个程序fifo_write、c读数据并打印出来。
//fifo、read、c
#include
#include
#include
#include
#include
#include
#include
#include
//#defineFIFO"fifo"
intmain()
{
intfdr,fd;
charbuf_r[]="HiLinux\n";
fd=mkfifo("fifo、txt",O_CREAT|O_RDWR|0666);
if(fd<0)
{printf("fifocreaterror(R)!
\n");
exit(-1);
}
fdr=open("fifo、txt",O_WRONLY|O_CREAT,0666);
if(fdr<0)
{
printf("openerror!
");
exit(-1);
}
if(write(fdr,buf_r,sizeof(buf_r))<0)
{
printf("writeerror");
exit(-1);
}
close(fdr);
close(fd);
return0;
}
#include
#include
#include
#include
#include
#include
#include
#include
//#defineFIFO"fifo"
intmain()
{
intfdw,fd;
charbuf[100];
memset(buf,0,sizeof(buf));
fdw=open("fifo、txt",O_RDONLY);
if(fdw<0)
{
printf("openerror(W)!
");
exit(-1);
}
//sleep
(2);
if(read(fdw,buf,100)<0)
{
printf("readerror(W)");
exit(-1);
}
printf("\n%s",buf);
close(fdw);
return0;
}
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Linux 系统 编程 实验 进程 通信