IPC: inter process communication
进程之间 的通信:实质---数据的交换
管道: pipe 无名管道 (亲缘关系的进程之间)
fifo 有名管道 (可以在没有亲缘关系的 进程间)
信号: signal kill -9 pid
消息队列: 在linux内核中, A 进程发送一个 message 挂在队列上
B 进程去队列上把 message 读走
ipcs 可以查看当前 linux系统内核中存在的消息队列
共享内存段:
信号量数组:
socket 通信: 在不同的电脑的 进程之间 通信 (网络编程)
1. 管道
在很久以前,进程之间的通信,可以用文件
缺点: 慢,消耗大
优点: 不需要再学习 IPC API函数
有人利用系统的 API , 但文件的内容不在磁盘上(在内存中)在内存中搞一个文件
1) 无名管道
#include <unistd.h>
int pipe(int pipefd[2]);
参数: 是一个数组: pipefd[0] ---->读 描述符
pipefd[1] ----->写 描述符
返回值: 0 成功 -1 失败
#include <stdio.h>
#include <unistd.h>
int main()
{
int fd[2];
char buf[100]={};
pipe(fd); // fd[0]读描述符,fd[1]写描述符
pid_t pid = fork();
if(pid == 0)
{
close(fd[0]);
write(fd[1],"hello",5);
}
else
{
close(fd[1]);
read(fd[0], buf, sizeof(buf));
printf("buf=%s\n",buf);
}
}
2) 有名管道
mkfifo fifo1
读写一个空的管道都会阻塞
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
const char *pathname: fifo的路径名
mode : 文件的权限
返回值: 0 成功,-1 失败
练习: 实现两个进程聊天: tom_from.c jerry_to.c
3 信号
linux 中的信号有哪些 : kill -l
china@ubuntu:/mnt/hgfs/share/shuqi/ipc$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM
15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP
20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
SIGHUP: 控制终端挂起请求或者 控制终端 死亡的时候。
SIGINT: CTRL+C 从键盘收到 SIGINT信号, 程序会终止
SIGQUIT: CTRL+\ 从键盘收到 SIGquit信号,程序会终止
SIGSEGV: 当 程序访问非法地址内存,收到 这个信号, 程序会终止
SIGKILL: kill -9 杀死进程的信号
SIGSTOP: 让进程暂停
SIGCONT: 让进程继续
SIGALRM: 闹钟信号, alarm()函数会参数这个信号,程序收到会终止
SIGCHLD: 在父进程中,如果收到这个信号,代表子进程结束了
SIGUSER1: 用户信号1 忽略
SIGUSER2: 用户信号2 忽略
进程收到以上的信号的时候,通常会有3中处理方式:
(1). 捕捉信号: 把一个信号 与 用户自定义的 处理函数 关联起来 signal(如果收到该信号,就执行那个函数)
(2). 默认行为: 收到信号的时候,采用 操作系统的默认行为(终止)
(3). 忽略该信号
linux 信号相关的API函数
发送信号: kill 函数 (可以发送给多个进程)
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
pid: 接收者
pid>0: 表示接收进程的PID
pid=0: 发送给本组的进程
pid=-1: 发送给所有进程(与权限发送的所有进程)
pid<-1: 发送给进程组(进程组id)= -pid
sig: 信号的id
返回值:0成功,-1失败
#include
unsigned int alarm(unsigned int seconds);
unsigned int seconds: 定时的秒数
当 seconds 时间到了,就发送一个 SIGALRM 信号 给 自己
alarm(0); ----> 如果闹钟时间还未到,取消闹钟
int raise(int sig); 发送sig 信号给自己
pause(); 等待一个信号,如果收到一个信号就返回
大部分的信号的默认行为,进程如果收到 信号的默认行大部分都是终止。
改变信号的处理方式: 捕捉信号
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
int signum: 要捕捉的信号
handler: 处理方式 :有3种
1. 自己写一个信号处理函数
2. SIG_IGN 忽略该信号
3. SIG_DFL 默认执行
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void my_handle(int sig)
{
printf("捕捉到了%d信号\n",sig);
}
int main()
{
alarm(4);
signal(SIGALRM,my_handle);
signal(SIGQUIT,SIG_DFL);
//关联 SIGINT my_handle() 起来了
pause();
}
练习:
司机售票员问题。
创建子进程代表售票员,父进程代表司机,同步过程如下:
售票员捕捉 SIGINT(代表开车 ctrl+c), 发SIGUSR1 给司机,司机打印 ("let's gogogo")
售票员捕捉 SIGQUIT(代表停车 ctrl+\), 发送SIGUSR2给司机,司 机打印("stop ths bus")
司机捕捉SIGTSTP(代表车到总站, ctrl + z), 发送 SIGUSR1给售票 员,售票员打印("please get off the bus")
子进程要捕捉: 售票员
signal: SIGINT, SIGQUIT, SIGUSR1
忽略哪些信号: SIGTSTP
父进程要捕捉:司机
signal: SIGTSTP,SIGUSR1, SIGUSR2
忽略哪些信号? SIGINT, SIGQUIT