无名管道
有名管道
信号简介
常用信号分析
signal_kill_raise函数
什么是进程间通信(ipc)
进程间通信
- 数据传输
- 资源共享
- 事件通知
- 进程控制
Linux系统下的ipc
- 早期unix系统ipc
- 管道
- 信号
- fifo
- system-v ipc(贝尔实验室)
- system-v 消息队列
- system-v 信号量
- system-v 共享内存
- socket ipc(BSD)
- posix ipc(IEEE)
- posix 消息队列
- posix 信号量
- posix 共享内存
无名管道
pipe函数
头文件:
#include <unistd.h>
函数原型:
int pipe(int pipefd[2]);
返回值:
成功:0
失败:-1
特点
- 特殊文件(没有名字),无法使用open,但是可以使用close。
- 只能通过子进程继承文件描述符的形式来使用
- write和read操作可能会阻塞进程
- 所有文件描述符被关闭之后,无名管道被销毁
使用步骤
- 父进程pipe无名管道
- fork子进程
- close无用端口
- write/read读写端口
- close读写端口
有名管道
mkfifo函数
头文件:
#include <sys/types.h>
#include <sys/state.h>
函数原型:
int mkfifo(const char *filename,mode_t mode)
返回值:
成功:0
失败:-1
特点
- 有文件名,可以使用open函数打开
- 任意进程间数据传输
- write和read操作可能会阻塞进程(有名管道里没有数据/数据被写满)
- write具有"原子性" (能写入完整数据)
使用步骤
- 第一个进程mkfifo有名管道
- open有名管道,write/read数据
- close有名管道
- 第二个进程open有名管道,read/write数据
- close有名管道
fifo_read.c
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#define Myfifo "/home/xiaolei/practice/system_program/5.fifo_read/myfifo"
int main(int argc , char * argv[])
{
char buff[4096];
int fd;
int nread;
if(access(Myfifo,F_OK) == -1)
{
if((mkfifo(Myfifo,0666)<0) && (errno != EEXIST))
{
printf("cannot creat fifo file\n");
exit(1);
}
}
fd = open(Myfifo,O_RDONLY);
if(fd == -1)
{
printf("open fifo file error\n");
exit(1);
}
//循环读取所有管道数据
while(1)
{
memset(buff,0,sizeof(buff));
if((nread = read(fd,buff,4096)) > 0)
{
printf("read '%s'from fifo \n",buff);
}
}
close(fd);
exit(0);
}
执行:
fifo_write.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define Myfifo "/home/xiaolei/practice/system_program/5.fifo_read/myfifo"
int main(int argc , char * argv[])
{
int fd;
char buff[4096];
int nwrite;
sscanf(argv[1],"%s",buff); //填充命令行第一个参数到buff
fd = open(Myfifo,O_WRONLY);
//向管道中写入字符串
if((nwrite = write(fd,buff,4096)) > 0)
{
printf("write '%s' to fifo \n",buff);
}
close(fd);
exit(0);
}
运行:
信号简介
信号的基本概念
软件模拟中断,进程接受信号后做出相应响应
怎么产生信号?
-
硬件
- 执行非法指令
- 访问非法内存
- 驱动程序
- …
-
软件
-
控制台:
- ctrl+c:中断信号
- ctrl+|:退出信号
- ctrl+z:停止信号
-
kill命令
-
程序调用kill()函数
-
信号的处理方式:
- 忽略:进程当信号从来没有发生过
- 捕获:进程会调用相应的处理函数,进行相应的处理
- 默认:使用系统默认处理方式来处理信号
常用信号分析
信号名 | 信号编号 | 产生原因 | 默认处理方式 |
---|---|---|---|
SIGHUP | 1 | 关闭终端 | 终止 |
SIGINT | 2 | ctrl+c | 终止 |
SIGQUIT | 3 | ctrl+\ | 终止+转储 |
SIGABRT | 6 | abort() | 终止+转储 |
SIGPE | 8 | 算术错误 | 终止 |
SIGKILL | 9 | kill -9 pid | 终止,不可捕获/忽略 |
SIGUSR1 | 10 | 自定义 | 忽略 |
SIGSEGV | 11 | 段错误 | 终止+转储 |
SIGUSR2 | 12 | 自定义 | 忽略 |
SIGALRM | 14 | alarm() | 终止 |
SIGTERM | 15 | kill pid | 终止 |
SIGCHLD | 17 | (子)状态变化 | 忽略 |
SIGTOP | 19 | ctrl+z | 暂停,不可捕获/忽略 |
pkill命令
signal_kill_raise函数
signal函数
头文件:
include<signal.h>
函数原型:
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum,sighandler_t handler);
参数:
- signum: 要设置的信号
- handler:
- SIG_IGN:忽略
- SIG_DFL:默认
- void (*sighandler_t)(int):自定义
返回值:
成功:上一次设置的handler
失败:SIG_ERR
kill函数
头文件:
#include <sys/types.h>
#include <signal.h>
原型函数:
int kill(pid_t pid,int sig);
参数:
- pid:进程id
- sig:要发送的信号
返回值:
成功:0
失败:-1
raise函数
头文件:
#include <signal>
原型函数:
int raise(int sig);
参数:
sig:发送信号
返回值:
成功:0
失败:非0