一、无名管道
1.1 Linux下进程间通信概述
1.2 无名管道通信
无名管道是内核空间实现的机制,只能用于亲缘进程间通信,无名管道的大小是64KB;
1.3 pipe函数
| 项目 |
内容 |
| 所需头文件 |
#include <unistd.h> |
| 函数原型 |
int pipe(int pipefd[2]); |
| 功能 |
创建单向数据通道(半双工通信方式)。数据只能从读端 pipefd[0] 读取,从写端 pipefd[1] 写入,方向不可逆转;数据先写入内核缓冲区,再由读进程从内核缓冲区读取。 |
| 参数 |
pipefd:用于存放管道读写两端的文件描述符的数组首地址 |
| 返回值(成功) |
0 |
| 返回值(失败) |
-1,并重置错误码 |
1.4 无名管道
| 类别 |
特点描述 |
| 通信范围 |
依托具有亲缘关系的进程间的文件描述符继承特性来实现通信(如父子进程、兄弟进程) |
| 数据传输方向 |
数据只能单向传输,符合半双工定义(一端读、一端写) |
| 内核缓冲区大小 |
多数 Linux 系统中默认大小为 64KB |
| lseek 限制 |
不能使用 lseek 函数(管道不是普通文件),调用会返回 -1 |
| 读端存在时(写满) |
写管道满则阻塞;存在约 4KB 空间时唤醒(Linux 内核为平衡效率与响应性的设计) |
| 读端不存在时(写) |
写管道会破裂,触发 SIGPIPE 信号 |
| 写端存在时(读) |
读管道时若无数据,则阻塞等待 |
| 写端不存在时(读) |
读管道时若无数据,则立即返回 0(非阻塞,类似读到文件结束) |
二、有名管道
2.1 有名管道通信
有名管道可以用于亲缘进程通信,也可以用于非亲缘进程通信,有名管道的大小是64KB;
2.2 mkfifo函数
| 项目 |
内容 |
| 所需头文件 |
#include <sys/types.h> #include <sys/stat.h> |
| 函数原型 |
int mkfifo(const char *pathname, mode_t mode); |
| 功能 |
创建有名管道(FIFO) |
| 参数 |
**pathname:**文件的路径和名字(只写名字则默认路径是当前路径)。如果管道文件已存在,则会报错(提示文件已存在) mode: 文件的权限。最终权限 = mode & ~umask |
| 返回值(成功) |
0 |
| 返回值(失败) |
-1,并重置错误码 |
2.3 unlink函数
| 项目 |
内容 |
| 所需头文件 |
#include <unistd.h> |
| 函数原型 |
int unlink(const char *pathname); |
| 功能 |
删除文件系统中的"文件名链接"(减少文件的硬链接计数,当计数归零且无进程打开时,删除文件内容) |
| 参数 |
**pathname:**文件的路径和名字(只写名字则默认路径是当前路径) |
| 返回值(成功) |
0 |
| 返回值(失败) |
-1,并重置错误码 |
2.4 有名管道
| 类别 |
特点描述 |
| 数据传输方向 |
数据只能单向传输,符合半双工定义;若要双向通信,需创建两个管道 |
| 内核缓冲区大小 |
多数 Linux 系统中默认大小为 64KB |
| lseek 限制 |
不能使用 lseek 函数(管道不是普通文件),调用会返回 -1 |
| 写操作 - 读端已打开时 |
写入数据时会尽可能写入(受管道缓冲区大小限制);若管道已满,写操作会阻塞直到有空间 |
| 写操作 - 阻塞期间读端关闭 |
会产生 SIGPIPE 信号(管道破裂) |
| 写操作 - 读端未打开(阻塞方式) |
写进程在 open() 调用时会阻塞,直到有读进程打开该 FIFO |
| 写操作 - 读端未打开(非阻塞方式) |
open() 调用会直接返回错误 |
| 读操作 - 写端已打开时 |
读取数据时,有多少读取多少;若管道为空,读操作会阻塞等待数据写入 |
| 读操作 - 写端未打开时 |
读进程在 open() 调用时会阻塞,直到有写进程打开该管道 |
| 读操作 - 写端曾打开但已关闭 |
读操作会读取剩下数据,读完后返回 0(不会阻塞,类似读到文件结束) |
| 读操作 - 非阻塞方式打开且无写端 |
open() 调用会直接返回成功 |
三、信号
先导
信号是中断的一种软件模拟,它是基于linux内核实现的;
用户可以给进程发信号,进程可以给进程发信号,linux内核也可以给进程发信号;
对信号处理的三种方式:默认、忽略、捕捉;
3.1 常用信号
| 信号名 |
含义 |
默认操作 |
| SIGKILL |
用来结束进程,且不能被捕捉和忽略 |
终止 |
| SIGSTOP |
用于暂停进程,且不能被捕捉和忽略 |
暂停进程 |
| SIGTSTP |
用于暂停进程,用户可键入 SUSP 字符(通常是 Ctrl+Z)发出此信号 |
暂停进程 |
| SIGCONT |
让进程进入运行态 |
继续运行 |
| SIGALRM |
通知进程定时器时间已到 |
终止 |
| SIGUSR1 / SIGUSR2 |
保留给用户程序使用 |
终止 |
| SIGCHLD |
当子进程退出时,给父进程发送该信号 |
忽略 |
3.2 signal函数
| 项目 |
内容 |
| 所需头文件 |
#include <signal.h> |
| 函数原型 |
typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler); |
| 功能 |
建立信号与处理方式的关联 |
| 参数 - signum |
信号的编号 |
| 参数 - handler |
处理方式: • SIG_IGN:忽略 • SIG_DFL:默认 • 传递函数地址:捕捉 |
| 返回值(成功) |
返回 handler 首地址 |
| 返回值(失败) |
返回 SIG_ERR,并重置错误码 |
3.3 raise函数
| 项目 |
内容 |
| 所需头文件 |
#include <signal.h> |
| 函数原型 |
int raise(int sig); |
| 功能 |
向自身发送指定的信号 |
| 参数 - sig |
要发送的信号的编号 |
| 返回值(成功) |
返回 0 |
| 返回值(失败) |
返回 非0 |
3.4 kill函数
| 项目 |
内容 |
| 所需头文件 |
#include <sys/types.h> #include <signal.h> |
| 函数原型 |
int kill(pid_t pid, int sig); |
| 功能 |
给任意进程发送信号 |
| 参数 - pid |
发送信号的目标: • >0:向 pid 对应的单个进程 发送信号(最常用场景) • 0:向同进程组 的所有进程发送信号 • -1:向所有有权限操作的进程 发送信号(init进程除外,避免影响系统核心进程) • < -1:给进程组ID等于 -pid 的进程发送信号 |
| 参数 - sig |
信号的编号 |
| 返回值(成功) |
0 |
| 返回值(失败) |
-1,并重置错误码 |
3.5 atoi函数
| 项目 |
内容 |
| 所需头文件 |
#include <stdlib.h> |
| 函数原型 |
int atoi(const char *nptr); |
| 功能 |
将字符串转换为整数 |
| 参数 - nptr |
要转换的字符串的首地址 |
| 返回值(成功) |
返回转换后的整数 |
| 返回值(失败) |
返回 0;如果转换后整数超出 int 范围,则行为未定义 |