一.基本概念
进程间通讯:进程之间交换数据的过程叫进程间通讯。
进程间通讯的方式:、
简单的进程间通讯:
命令行:父进程经过exec函数建立子进程时能够附加一些数据
环境变量表:父进程经过exec函数建立子进程顺便传递一张环境变量表
信号:父子进程之间能够根据进程号相互发送信号,进程简单通讯
文件:一个进程向文件中写入数据,另外一个进程从文件中读取出来。
命令行,环境变量只能单向传递,信号太过于简单,文件通讯不能实时。
XSI通讯方式:X/open 计算机制造商组织。
共享内存,消息队列,信号量,
网络进程间通讯方式:
网络通讯就是不一样机器的进程间通讯方式
传统的进程间通讯方式:管道
二.管道
1.管道是一种古老的通讯方式(基本上再也不使用)
2.早期的管道是一种半双工,如今大多数是全双工的
3.有名管道(管道是以文件的方式存在的)
建立管道文件:
命令mkfifo
函数mkfifo
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
管道通讯的编程模式:
进程A 进程B
建立管道mkfifo
打开管道文件open 打开管道
写/读数据write/read 读/写数据
关闭管道close 关闭管道
4.无名管道:由内核帮助建立,只返回管道的文件描述符,看不到管道文件,这种管道只能用于fork建立的父子进程之间
int pipe(int pipefd[2]);
pipefd[0]用来读数据
pipefd[1]用来写数据
练习:使用无名管道让父子进程通讯
三.XSI IPC进程间通讯
1.XSI通讯是依靠内核的IPC对象进程通讯
2.每个IPC对象都有一个IPC标识(相似文件描述符),IPC标识符是一个非负整数。
3.IPC对象必需要先建立,建立后才能进程获取,设置,操做,删除。
4.建立IPC对象必需要提供一个键值(key_t),键值是建立获取IPC对象的依据
5.产生键值的方法:
固定的字面值:1980014
使用函数计算:ftok(项目路径,项目id)
使用宏让操做系统随机分配:IPC_PRIVTE
必须把获取到的IPC对象标识符记录下来,告诉其余进程
6.XSI能够建立的IPC对象有:
共享内存,消息队列,信号量
四.共享内存
1.由内核维护一块共享的内存区域,其余进程把本身的虚拟地址映射到这块内存,而后多个进程之间共享这块内存了。
2.这种进程间通讯的好处是不须要信息复制
,它是进程间通讯最快的一种方式。
3
.这种方式会面临同步的问题,须要与其余的通讯方式配合,最合适的方式就是信号。
共享内存的编程模式:
1.进程之间要约定一个键值
进程A 进程B
建立共享内存
加载共享内存 加载共享内存
卸载共享内存 卸载共享内存
销毁共享内存
int shmget(key_t key, size_t size, int shmflg);
功能:建立共享内存
size:大小
模式:
返回值:IPC对象标识符(相似于文件描述符)
void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:加载共享内存()
shmid:shmget的返回值
shmaddr:进程提供的虚拟地址,也能够为NULL,若是为空,操做系统会自动选择一块地址映射
shmflg:
SHM_RDONLY:映射内存的权限为只读
SHM_REMAP:映射已经存在的内存共享
SHM_RND:当shmaddr为空时自动分配
mode_flag:权限
int shmdt(const void *shmaddr);
功能:这个地址对应的共享内存取消映射关系
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:控制/销毁共享内存
cmd:
IPC_STAT:获取共享内存的属性
IPC_SET:设置共享内存的属性
IPC_RMID:删除共享内存
buf:
记录共享内存属性的对象
五.消息队列
1.
消息队列是一个由系统内核负责存储和管理,并经过IPC对象标识符获取的数据链表
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
msgflg:
建立IPC_CREAT | IPC_EXCL
获取:0
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:向消息队列发送消息
msqid:msgget的返回值
msgp:消息(消息类型+消息内容)的首地址
msgsz:消息内容的长度(不包含消息类型)
msgflg:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
功能:从消息队列接收消息
msgp:存储消息的缓冲区
msgsz:要接收的消息长度
msgtyp:要接收消息的类型,(包含在消息的前四个字节)
msgflg:
MSG_NOERROR:当消息的实际长度大于msgsz,则按照msgsz长度截取再发送,不然产生错a
MSG_NOWAIT:若是想要接收的消息不存在,则直接返回。
不然阻塞等待。
MSG_EXCEPT:从消息队列中接收第一个不是msgtype类型的第一个消息
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
功能:控制/销毁消息队列
cmd:
IPC_STAT:获取消息队列的属性
IPC_SET:设置消息队列的属性
IPC_RMID:删除消息队列
六.IPC相关命令:
ipcs -m 查看共享内存
ipcrm -m id 删除共享内存
ipcs -q 查看消息队列
ipcrm -q id 删除消息队列
七.信号量
信号量(信号灯),能够看成进程与进程之间共享的全局变量,通常用来为共享的资源计数。
信号量的使用方法:
1.进程A,建立信号量,并设置信号量的初始值(设置资源数)
2.进程B,获取信号量,查看信号量(查询剩余资源的数量),减小信号量(使用资源),增长信号量(资源使用完毕归还)
3.当一个进程减小信号量时,若是不能减(资源使用完毕),则进程能够进入等待状态,当信号量可以被减的时候(其余进程把资源还回来了),进程会被唤醒
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
功能:建立获取获取信号量
nsems:信号量的数量
semflg:
IPC_CREAT
IPC_EXCL
0644之类的权限码
int semop(int semid, struct sembuf *sops, unsigned nsops);
功能:对信号量增长或减小
struct sembuf {
unsigned short sem_num;
short sem_op;
short sem_flg; // IPC_NOWAIT标识不阻塞
}
int semctl(int semid, int semnum, int cmd, ...);
功能:对信号量的控制或释放
semnum:信号量的编号
cmd:
IPC_SET 设置信号量的属性
IPC_STAT 设置信号量的属性
IPC_RMID 删除信号量
IPC_INFO 获取信号量的信息