进程间通信主要分为两个大类:
1、Unix继承的通信方式:信号、管道
2、system V IPC对象:共享内存、消息队列、信号灯集、套接字(网络编程使用)
目录
一、管道
1、无名管道
2、有名管道
二、信号
1、定时器
2、暂停
3、捕获信号
三、共享内存
实现流程
1、key值的获取
2、创建或者打开共享内存——shmget
3、映射共享内存——shmat
4、访问共享内存
5、取消映射——shmdt
6、删除共享内存——shmctl
四、消息队列
实现流程
1、创建、打开消息队列——msgget
2、发送消息——msgsnd
3、接收消息——msgrcv
4、操作消息队列——msgctl
五、信号灯集
实现流程:
1、获取信号灯——semget
2、设置信号灯初值(或其它操作:比如删除)——semctl
3、实现PV操作——semop
六、套接字
文件系统中不可见(不存在-p文件)
特点:
1、创建之后在文件系统中不可见
2、以半双工的方式进行通信
3、拥有固定的读端和写段
4、只能用于具有亲缘关系的进程间通信读特性:
写端存在:
管道有数据:返回读到的字节数
管道无数据:程序阻塞
写段不存在:
管道有数据:返回读到的字节数
管道无数据:返回0
写特性:
读端存在:
管道有空间:返回写入的字节数
管道无空间:程序阻塞,直到有空间为止
读端不存在:
无论管道是否有空间,管道破裂,管道破裂进程终止
#include
int pipe(int pipefd[2]);
参数:
pipefd:存放无名管道读端和写端的数组首地址
pipefd[0]——读端
pipefd[1]——写端返回值:
成功返回0,失败返回-1
文件系统中可见(存在-p文件)
有名管道创建之后会在文件系统中以管道文件的形式存在
有名管道可以用于任意两个进程间通信,没有固定的读写端
#include
#includeint mkfifo(const char *pathname, mode_t mode);
参数:
pathname:创建管道文件的文件名
mode:创建管道文件的权限
返回值:
成功返回0,失败返回1
信号:是中断在软件层次上的一种模拟
信号的处理方式:
默认处理:
忽略处理:
捕获信号:常用信号指令:
kill
1、定时器
定时时间到时,当前进程会接收到编号为14的信号——SIGARLM
一个进程中最多只能存在一个定时器相关函数:——alarm
#include
unsigned int alarm(unsigned int seconds);
参数:
second:定时秒数
返回值:
成功返回0或者上一个定时器剩余的时间
2、暂停
#include
int pause(void);
功能:阻塞在当前位置,等待定时结束
3、捕获信号
#include
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
参数:
signum:指定信号
hand1er:信号处理函数
SIG_IGN:选择以忽略方式处理指定信号
SIG_DEF:选择以默认方式处理指定信号
父进程回收子进程
是所有进程间通信效率最高的一种通信机制(将需要的内核层数据映射到用户层实现的)
#include
#includekey_t ftok(const char *pathname, int proj_id);
参数:
pathname:任意路径
proj_id:任意字符返回值:
成功返回key值,失败返回-1
#include
#includeint shmget(key_t key, size_t size, int shmflg);
参数:
key:通过ftok得到的key或者使用IPC_PRIVATE(创建私有共享内存)
size:共享内存的大小
shmflg:创建共享内存权限,一般填 0664 | IPC_CREAT返回值:
成功返回得到共享内存ID号,失败返回-1
#include
#includevoid *shmat(int shmid, const void *shmaddr, int shmflg);
参数:
shmid:共享内存ID
shmaddr:映射地址,NULL表示系统自动分配
shmflg:
SHM_REDONLY —— 只读
0 —— 读写返回值:
成功返回映射地址,失败返回(void *)-1
访问shmat返回的地址空间即可
#include
#includeint shmdt(const void *shmaddr);
参数:
shmaddr:表示要取消映射的地址返回值:
成功返回0,失败返回-1
#include
#includeint shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数:
shmid:共享内存id号
cmd:操作共享内存的命令
IPC_STAT:获取共享内存的信息,需要用到第三个参数
IPC_SET:设置共享内存信息
IPC_RMID:删除共享内存,第三个参数填空(映射全部取消之后才会删除)返回值:
成功返回0,失败返回-1
多个进程可同时向一个消息队列发送消息,也可以同时从一个消息队列中接收消息。发送进程把消息发送到队列尾部,接受进程从消息队列头部读取消息,消息一旦被读出就从队列中删除。
#include
#include
#includeint msgget(key_t key, int msgflg);
参数:
key:通过ftok创建的key值或者使用IPC_PRIVATE创建私有的消息队列
shmflg:创建共享内存权限,一般填 0664 | IPC_CREAT
返回值:
成功返回消息队列id号,失败返回-1
例:
int msgid = msgget(IPC_PRIVATE, 0664)
#include
#include
#includeint msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数:
msqid:消息队列id
msgp:跟发送消息相关的结构体的首地址
msgsz:消息结构体中正文内容的大小
msgflg:
0——表示以阻塞方式发送内容
IPC_NOWAIT——以非阻塞方式发送内容返回值:
成功返回0,失败返回-1
msgp用法:
#define LEN (sizeof(MSG) - sizeof(long))typedef struct msgbuf
{
long mtype;
char mtext[N];
}MSG;MSG msg;
char buf[N] = {0};
msg.mtype = 100;
fgets(buf, N, stdin);
strcpy(msg.mtest, buf)
msgsnd(msgid, &msg, LEN, 0);
#include
#include
#includessize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
参数:
msqid:消息队列id
msgp:接收消息相关的结构体的首地址
msgsz:消息结构体中正文内容的大小
msgflg:
0——表示以阻塞方式接收内容
IPC_NOWAIT——以非阻塞方式接收内容
#include
#include
#includeint msgctl(int msqid, int cmd, struct msqid_ds *buf);
cmd:操作共享内存的命令
IPC_STAT:获取共享内存的信息,需要用到第三个参数
IPC_SET:设置共享内存信息
IPC_RMID:删除共享内存,第三个参数填空(映射全部取消之后才会删除)
信号灯与其他进程间通信方式不大相同,它主要提供对进程间共享资源访问控制机制。相当于内存中的标志,进程可以根据它判定是否能够访问某些共享资源,同时,进程也可以修改该标志。除了用于访问控制外,还可用于进程同步。
#include
#include
#includeint semget(key_t key, int nsems, int semflg);
参数:
key:产生信号灯id需要使用的键值,可以用IPC_PRIVATE或者ftok 来获取
nsems:信号灯集中包含信号的个数
semflg:标志位 设置信号灯权限 例如:创建需要添加IPC_CREAT标志位
返回值:
成功返回信号灯ID号,失败返回-1
#include
#include
#includeint semctl(int semid, int semnum, int cmd, ...);
参数:
semid:信号灯标识id
semnum:要控制的信号灯编号(从0开始)
cmd:控制命令
IPC_RMID:删除
IPC_SET:设置信号灯相关属性
...:可变参数,如果第三个参数是IPC_RMID则第四个参数可以不传
如果第三个参数是IPC_SET则需要传递第四个参数
参数类型可以是一个共用体:
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
#include
#include
#includeint semop(int semid, struct sembuf *sops, size_t nsops);
参数:
struct sembuf
{
unsigned short sem_num;
short sem_op
short sem_flg;
}
sem_num:信号灯编号
sem_op:
1 :表示V操作(释放资源)
-1 :表示P操作(申请资源)
sem_flg:
通常为0表示阻塞等待
nsops:表示要控制多少个灯
主要用于网络编程中,也可以用于进程间通信