Linux系统编程实验六进程间通信.docx

上传人:b****4 文档编号:5427085 上传时间:2023-05-08 格式:DOCX 页数:14 大小:149.91KB
下载 相关 举报
Linux系统编程实验六进程间通信.docx_第1页
第1页 / 共14页
Linux系统编程实验六进程间通信.docx_第2页
第2页 / 共14页
Linux系统编程实验六进程间通信.docx_第3页
第3页 / 共14页
Linux系统编程实验六进程间通信.docx_第4页
第4页 / 共14页
Linux系统编程实验六进程间通信.docx_第5页
第5页 / 共14页
Linux系统编程实验六进程间通信.docx_第6页
第6页 / 共14页
Linux系统编程实验六进程间通信.docx_第7页
第7页 / 共14页
Linux系统编程实验六进程间通信.docx_第8页
第8页 / 共14页
Linux系统编程实验六进程间通信.docx_第9页
第9页 / 共14页
Linux系统编程实验六进程间通信.docx_第10页
第10页 / 共14页
Linux系统编程实验六进程间通信.docx_第11页
第11页 / 共14页
Linux系统编程实验六进程间通信.docx_第12页
第12页 / 共14页
Linux系统编程实验六进程间通信.docx_第13页
第13页 / 共14页
Linux系统编程实验六进程间通信.docx_第14页
第14页 / 共14页
亲,该文档总共14页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

Linux系统编程实验六进程间通信.docx

《Linux系统编程实验六进程间通信.docx》由会员分享,可在线阅读,更多相关《Linux系统编程实验六进程间通信.docx(14页珍藏版)》请在冰点文库上搜索。

Linux系统编程实验六进程间通信.docx

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(intfiledes[2]);

函数说明(参数):

pipe()会建立管道,并将文件描述词由参数filedes数组返回。

           filedes[0]为管道里的读取端,filedes[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;

}

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 党团工作 > 入党转正申请

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2