管道与信号
来源:互联网 发布:微信拼图游戏源码 编辑:程序博客网 时间:2024/06/05 10:50
一、管道的概念
管道是单向的、先进先出的,它把一个进程的输出和另一个进程的输入连接在一起。一个进程(写进程)在管道的尾部写入数据,另一个进程(读进程)从管道的头部读出数据。管道包括无名管道和有名管道两种,前者用于父进程和子进程间的通信,后者可用于运行于同一系统中的任意两个进程间的通信。
1、无名管道
pipe
函数原型:int pipe(int filedis[2]);
函数参数:新建的两个描述符filedis数组返回,filedis[0]表示管道的读取端,fds[1]表示管道的写入端
返回值:成功返回0,出错返回-1
头文件:#include<unistd.h>
#include <unistd.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>int main(){int pipe_fd[2];if(pipe(pipe_fd)<0){printf("pipe create error\n");return -1;}else printf("pipe create success\n");close(pipe_fd[0]);close(pipe_fd[1]);}
2、管道读写
管道用于不同进程间通信。通常先创建一个管道,再通过fork函数创建一个子进程,该子进程会继承父进程所创建的管道
#include <unistd.h>#include <sys/types.h>#include <errno.h>#include <stdio.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) //子进程 OR 父进程?{printf("\n");close(pipe_fd[1]);sleep(2); /*为什么要睡眠*/if((r_num=read(pipe_fd[0],buf_r,100))>0){printf( "%d numbers read from the pipe is %s\n",r_num,buf_r);}close(pipe_fd[0]);exit(0); }else if(pid>0){close(pipe_fd[0]);if(write(pipe_fd[1],"Hello",5)!=-1)printf("parent write1 Hello!\n");if(write(pipe_fd[1]," Pipe",5)!=-1)printf("parent write2 Pipe!\n");close(pipe_fd[1]);sleep(3);waitpid(pid,NULL,0); /*等待子进程结束*/exit(0);}return 0;}
3、有名管道通信
有名管道和无名管道基本相同,但也有不同点:无名管道只能由父子进程使用;
但是通过命名管道,不相关的进程也能交换数据。
函数原型:int mkfifo(const char *filename,mode_t mode)
函数作用:创建有名管道
函数参数:filename:有名管道的路径,名称
mode:管道的方式
几种方式:O_NONBLOCK FIFO打开的时候,非阻塞
O_RDONLY 只读
O_WRONLY 只写
O_RDWR 读写
返回值:成功为0,出错为-1
一旦创建了一个FIFO,就可用open打开它,一般的文件访问函数(close、read、write等)都可用于FIFO
注意:
FIFO文件在使用上和普通文件有相似之处,但是也有不同之处:
(1)读取fifo文件的进程只能以”RDONLY”方式打开fifo文件。
(2)写fifo文件的进程只能以”WRONLY”方式打开fifo
(3) fifo文件里面的内容被读取后,就消失了。但是普通文件里面的内容读取后还存在。
4、有名管道的读写
#include <sys/types.h>#include <sys/stat.h>#include <errno.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#define FIFO "/tmp/myfifo"main(int argc,char** argv){char buf_r[100];int fd;int nread;/* 创建管道 */if((mkfifo(FIFO,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST))printf("cannot create fifoserver\n");printf("Preparing for reading bytes...\n");memset(buf_r,0,sizeof(buf_r));/* 打开管道 */fd=open(FIFO,O_RDONLY|O_NONBLOCK,0);if(fd==-1){perror("open");exit(1);}while(1){memset(buf_r,0,sizeof(buf_r));if((nread=read(fd,buf_r,100))==-1){if(errno==EAGAIN)printf("no data yet\n");}printf("read %s from FIFO\n",buf_r);sleep(1);}pause(); /*暂停,等待信号*/unlink(FIFO); //删除文件}
#include <sys/types.h>#include <sys/stat.h>#include <errno.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#define FIFO_SERVER "/tmp/myfifo"main(int argc,char** argv){int fd;char w_buf[100];int nwrite;/*打开管道*/fd=open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,0);if(argc==1){printf("Please send something\n");exit(-1);}strcpy(w_buf,argv[1]);/* 向管道写入数据 */if((nwrite=write(fd,w_buf,100))==-1){printf("The FIFO has not been read yet.Please try later\n");}else printf("write %s to the FIFO\n",w_buf);}
二、信号
1、信号(signal)机制是Unix系统中最为古老的进程间通信机制,很多条件可以产生一个信号(信号分类):
(1)、当用户按某些按键时,产生信号
(2)、硬件异常产生信号:除数为0、无效的存储访问等等。这些情况通常由硬件检测到,将其通知内核,然后内核产生适当的信号通知进程,例如,内核对正访问一个无效存储区的进程产生一个SIGSEGV信号
(3)、进程用kill函数将信号发送给另一个进程
(4)、用户可用kill命令将信号发送给其他进程
信号处理流程图如下:
下面是几种常见的信号类型:
§SIGHUP:从终端上发出的结束信号
§SIGINT:来自键盘的中断信号(Ctrl-C)
§SIGKILL:该信号结束接收信号的进程,杀死进程
§ SIGTERM:kill命令发出的信号
§SIGCHLD:子进程停止或结束时通知父进程
§SIGSTOP:来自键盘(Ctrl-Z)或调试程序的停止执行信号,暂停进程
2、信号处理
当某信号出现时,将按照下列三种方式中
的一种进行处理:
(1)、忽略此信号
大多数信号都按照这种方式进行处理,但有两种信号决不能被忽略,它们是:SIGKILL\SIGSTOP。这两种信号不能被忽略的原因是:它们向超级用户提供了一种终止或停止进程的方法。
(2)、执行用户希望的动作
通知内核在某种信号发生时,调用一个用户函数。在用户函数中,执行用户希望的处理
(3)、执行系统默认动作
对大多数信号的系统默认动作是终止该进程
3、信号发送
发送信号的主要函数有kill和raise。
信号发送:kill
函数的作用:传送信号给指定的进程
函数的原型:int kill(pid_t pid,int sig)
函数的参数:(1)、pid>0
将信号发送给进程ID为pid的进程。
(2)、pid == 0
将信号发送给同组的进程。
(3)、pid < 0
将信号发送给其进程组ID等于pid绝对值的进程。
(4)、pid ==-1
将信号发送给所有进程。
#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <sys/types.h>#include <sys/wait.h>int main(){ pid_t pid; int ret; if((pid=fork()) < 0) { perror("fork"); exit(1); } if(pid == 0) { raise(SIGSTOP); exit(0); } else { printf("pid=%d\n", pid); if((waitpid(pid, NULL, WNOHANG)) == 0) { kill(pid,SIGKILL); printf("kill %d\n", pid); } else { perror("kill"); } }}
raise
函数的功能:发送信号给自身
函数的原型:int raise(int sig)
头文件:#include <signal.h>
#include <sys/types.h>#include <sys/stat.h>#include <errno.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <signal.h>int main(){ pid_t pid; int ret; if((pid= fork()) < 0) { printf("Fork error.\n"); exit(-1); } if(pid == 0) { printf("child (pid:%d) is waiting for any signal\n.", getpid()); raise(SIGSTOP); exit(0); } else { if((waitpid(pid, NULL, WNOHANG)) == 0) { kill(pid, SIGKILL); printf("parent kill child process %d\n", pid); } waitpid(pid, NULL, 0); exit(0); }}
Kill既可以向自身发送信号,也可以向其他进程发送信号。与kill函数不同的是,raise函数是向进程自身发送信号.
alarm
函数原型:unsigned intalarm(unsigned int seconds)
头文件:#include<unistd.h>
参数说明:Seconds:
经过了指定的seconds秒后会产生信号SIGALRM。
v 注意:每个进程只能有一个闹钟时间.如果在调用alarm时,以前已为该进程设置过闹钟时间,而且它还没有超时,以前登记的闹钟时间则被新值代换
v 如果有以前登记的尚未超过的闹钟时间,而这次seconds值是0,则表示取消以前的闹钟
pause:
函数原型: int pause(void)
函数作用: 使调用进程挂起直至捕捉到一个信号。
4、信号处理
当系统捕捉到某个信号时,可以忽略该信号或是使用指定的处理函数来处理该信号,或者使用系统默认的方式。
信号处理的主要方法有两种,一种是使用简单的signal函数,另一种是使用信号集函数组。
signal
函数作用:信号处理函数,设置信号处理方式
函数原型:void (*signal(int signo, void (* sighandler_t)(int)))(int)
typedef void(*sighandler_t)(int) sighandler_t
signal(intsignum, sighandler_t handler))
#include <signal.h>#include <stdio.h>#include <stdlib.h>/*自定义信号处理函数*/void my_func(int sign_no){if(sign_no==SIGBUS)printf("I have get SIGBUS\n");}int main(){printf("Waiting for signal SIGBUS \n ");/*注册信号处理函数*/signal(SIGBUS,my_func);pause();//将进程挂起直到捕捉到信号为止exit(0);}
- 信号与管道
- 管道与信号
- 管道与信号
- 管道与信号
- 信号与命名管道
- linux 进程间通信一(管道与信号)
- linux进程的信号通信与进程的管道通信
- linux下c编程进程通信-管道与信号
- Linux进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)
- Linux进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)
- Linux进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)
- Linux进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)
- Linux进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)
- Linux进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)
- 管道破裂信号处理。
- 信号和管道
- 管道 信号 消息队列
- IPC 管道 信号
- windows自带局域网扫描IP
- Springboot 之 使用Scheduled做定时任务
- JSTL中日期转换 JSP 页面显示日期格式设置
- struct和typedef struct
- Java基础 equals()、hashCode()和 == 区别
- 管道与信号
- 文件file类的使用和异常
- 深入解析淘宝Diamond之客户端架构
- codeforces 718E. Matvey's Birthday
- test-欢迎使用CSDN-markdown编辑器
- Tomcat + Spring-framework MVC配置简介
- 1009. 说反话 (20)——stack<struct/class>、sscanf()
- Bootstrap+JavaScript实现广告轮播
- MySQL Limitations Part 1: Single-Threaded Replication [MySQL 短板 1]