Linux进程间通信学习笔记
进程间通信
进程间通信(IPC)是指在不同进程之间传播或交换信息
IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信息量、共享存储、Socket、Streams等。其中Socket、Streams支持不同主机上的两个进程IPC
无名管道
通常指无名管道,是UNIX系统IPC最古老的形式
特点
- 半双工(只能同时进行一组读写),具有固定的读端和写端
- 只能用于具有亲缘关系的进程之间的通信(父子进程/兄弟进程)
- 可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write等函数。但它不是普通的文件,不属于其他任何文件系统,只存在内存中。
- 管道数据被读取,就没了
原型
#include <unistd.h>
int pipe(int fd[2]);
//返回值:若成功返回0,失败返回-1
当一个管道建立时,其会创建两个文件描述符:
fd[0]为读而打开,fd[1]为写而打开 用close/write/read 操作
读管道 会等到 管道内有数据再读
命名管道 FIFO
命名管道,是一种文件类型
特点
- FIFO可以在无关的进程之间交换数据,与无名管道不同
- FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中
原型
mode与open的mode相同。一旦创建FIFO,就可以用一般的文件I/O函数操作它
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
当open一个FIFO时,是否设置非阻塞标志(O_NONBLOCK)的区别
- 若没指定O_NOBLOCK(默认),只读open要阻塞到某个其他进程为写而打开此FIFO。只写同理
- 若制定了O_NONBLOCK,则只读open立即返回。而只写open将出错返回-1。如果没有进程已经为读而打开该FIFO,其errno置ENXIO。
消息队列
消息列表,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
特点
- 消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级
- 消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除
- 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取
原型
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
//创建或打开消息队列:成功返回队列ID,失败返回-1
//flg 中还要包括权限
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
//添加消息:成功返回0,失败返回-1
size_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
//读取消息:成功返回消息数据长度,失败返回-1
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
//控制消息队列:成功返回0,失败返回-1
//msgctl可以清除消息队列 IPC_RMID
在以下两种情况下,msgget将创建一个新的消息列表:
- 如果没有与键值key相对应的消息队列,且flag中包含了IPC_CREAT标志位
- key参数为IPC_PRIVATE
ftok
系统IPC键值的格式转换函数
系统建立IPC通讯(消息队列、信号量和共享内存)时必须指定一个ID值。通常情况下,该id值通过ftok函数得到。
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
共享内存
- 创建/打开共享内存
- 映射
- 数据操作
- 释放共享内存
原型
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
//创建或获取一个共享内存:成功返回共享内存ID,失败返回-1
void *shmat(int shmid, const void *shmaddr, int shmflg);
//连接共享内存到当前进程的地址空间:成功返回指向共享内存的指针,失败返回-1
int shmdt(const void *shmaddr);
//断开与共享内存的连接:成功返回0,失败返回-1
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
//控制共享内存的相关信息:成功返回0,失败返回-1
//IPC_RMID
共享内存大小必须以兆(1024)对齐
信号
对于Linux来说,实际信号是软中断
信号的处理方式有三种:忽略、捕捉、默认动作
- 忽略信号,大多数信号能使用这种方式处理,但有两种不能被忽略(SIGKILL和SIGSTOP)
- 捕捉信号,写一个信号处理函数,告诉内核
- 默认动作,man 7 signal
ps -aux|grep XXX 查看进程
kill -9 数字 杀死进程
信号处理函数的注册
入门函数:signal
发:kill() 操作函数:signal()
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_thandler);
//SIG_IGN 忽略
高级函数:sigaction
收信号:1.用什么绑定函数 2.如何读出消息
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
//oldact 做备份
struct sigaction {
void (*sa_handler)(int);
//配置信号处理程序,不接受任何数据,SIG_IGN为忽略
void (*sa_sigaction)(int, siginfo_t *, void *);
//配置信号处理程序,能够接收额外数据
//配置1.num 2.结构体 3.指针(NULL无数据 非NULL有数据)
//2.结构体 pid谁发 int数据
sigset_t sa_mask;
//阻塞关键字的信号集,可以再调用捕捉函数之前,把信号添加到信号阻塞
int sa_flags;
//影响信号的行为 SA_SIGINFO标识能够接收数据
};
发信号:1.用什么发 2.怎么放入消息
sigqueue
#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);
union sigval {
int sival_int;
void *sival_ptr;
};
信号处理发送函数
信号量
是一个计数器,用于实现进程间的互斥与同步,而不是用于存储进程间通信数据
特点
- 信号量用于进程间同步,若要在进程间传递数据需要结合共享内存
- 信号量基于操作系统的PV操作,程序对信号量的操作都是原子操作
- 每次对信号量的PV操作不仅限于对信号量值加1或减1,可以加减任意正整数
- 支持信号量组
临界资源
多道程序系统中存在许多进程,它们共享各种资源,然而有很多资源一次只能供一个进程使用。一次仅允许一个进程使用的资源称为临界资源。
信号量集
P操作:拿锁 semop
V操作:放锁 semop
原型
Linux下的信号量函数都是在通用的信号量数组上进行操作,而不是在一个单一的二值信号量上进行操作
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
//创建或或获取一个信号量组:成功返回信号量集ID,失败返回-1
int semop(int semid, struct sembuf *sops, unsigned nsops);
//对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
int semctl(int semid, int semnum, int cmd, ...);
//控制信号量的相关信息 cmd初始化SETVAL
//cmd销毁IPC_RMID
struct sembuf
{
unsigned short sem_num; /* 信号量集中的第几个信号量 */
short sem_op; /* +- 锁*/
short sem_flg; /*SEM_UNDO维护进程对信号量的调整值*/
}
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */
};//semctl第四个参数 设置val(锁的数量)
上一篇: MFC学习笔记-进程间通信
下一篇: “React组件间通信”学习笔记