Linux系统基础(进程间通信)

一、基本概念

什么是进程间通信:是指两个或多个进程间交换数据的过程叫进程间通信
为什么需要进程间通信?
当需要多个进程协同工作高效率完成任务时,因为每个进程都是一个独立的个体(资源单位),进程之间就需要通信。
进程间通信方式:

  1. 简单进程间通信
    命令行参数
    环境变量表
    信号
    文件
  2. 传统进程间通信
    管道
  3. XSI进程间通信
    信号量、共享内存、消息队列
  4. 网络进程间通信
    socket

二、传统的进程通信

管道是UNIX系统最古老的通信方式(基本不再使用),历史上的管道通常是半双工(只允许数据单向导通)
现在的系统大多是全双工,数据可以双向流通

  1. 有名管道(创建实体文件)
    命令:mkfifo
    函数:mkfifo
    int mkfifo(const char *pathname, mode_t mode);
    功能:创建管道文件
    pathnanme:文件路径
    mode:权限
    返回值:成功返回0 失败返回-1
    编程模型
    进程A | 进程B
    创建管道 (mkfifo) | …
    打开管道 (open) | 打开管道
    读/写数据 (read/write) | 读写数据
    关闭管道 (close) | 关闭管道
    删除管道 (unlink) | …
  2. 无名管道(用于通过fork创建的父子进程间通信)
    int pipe(int pipefd[2]);
    功能:创建无名管道
    pipefd:用来存储内核返回的文件描述符
    pipefd[0]:读操作
    pipefd[1]:写操作
    1、使用有名管道进行通信
    管道创建者读对方写
    2、使用无名管道,父进程读,子进程写

三、XSI进程间通信

X/open组织为UNIX系统设计的一套进程间通信机制,有共享内存、消息队列、信号量

  1. ipc标识
    内核会为每个XSI的进程间通信对象维护一个IPC对象
    该对象通过一个非负整数来引用(类似文件描述符)。
    与文件描述符不同的是,每用一个IPC对象标志符就持续+1,达到最大值时从0开始
    IPC标识需要程序员自己创建(类似于创建文件)
  2. IPC键值
    创建IPC键值的依据(类似创建文件的文件名),也是一个非负整数
    1、自定义(不建议,可能会冲突)。
    2、自动生成(项目路径,项目编号)
    key_t ftok(const char *pathname, int proj_id);
    项目路径一定要是有效路径,生成IPC键值依靠的是路径而不是字符串
  3. IPC对象的创建
    IPC_PRIVATE 创建IPC对象时永远创建成功
    IPC_CREAT 存在则获取,不存在则创建
    IPC_EXCL 如果对象已经存在,则创建失败
  4. IPC对象销毁控制用到的宏
    IPC_STAT 获取对象的属性
    IPC_SET 设置IPC对象的属性
    IPC_RMID 删除IPC对象

四、共享内存

共享内存就是在内核中开辟一块由IPC对象管理,进程A和进程B都用自己的虚拟地址
与他的进程映射,这样他就共享了一块内存,然后就可以通信
特点:

  1. 不需要复制信息,最快的一种进程间通信机制
  2. 需要考虑同步问题(必须借助其他机制,如信号)

编程模型:
进程A 进程B
生成IPC键值 ftok 生成IPC键值ftok ftok
创建共享内存 shmget 获取共享内存 shmget
映射共享内存 shmat 映射共享内存 shmat
使用共享内存 *ptr 使用共享内存 *ptr
取消映射共享内存 shmdt 取消映射 shmdt
删除共享内存 shmctl …

int shmget(key_t key, size_t size, int shmflg);
功能:创建/获取共享内存
key:IPC键值
size:共享内存的大小最好是4096的整数倍
shmflg:
IPC_CREAT创建
IPC_EXCL 如果存在则创建失败
void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:映射共享内存
shmid:共享内存标识,shmgt返回值
shmaddr:进程提供的虚拟地址,与内核中的内存映射用的,也可以时NULL 内核会自动选择一个地址映射
shmflg:
SHM_RDONLY 只读权限
SHM_RND shmaddr为不为空时向下取整页

void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:取消虚拟地址与共享内存的映射
shmaddr:被映射过的虚拟内存

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:删除共享内存 获取/设置共享内存的属性
shmid:共享内存标志符
cmd:
IPC_STAT 获取共享内存的属性
IPC_SET 设置共享内存的属性
IPC_RMID 删除共享内存对象
struct shmid_ds {
struct ipc_perm shm_perm; 内存所有者以及权限
size_t shm_segsz; 内存的大小 字节为单位
time_t shm_atime; 最后的映射时间
time_t shm_dtime; 最后的取消映射的时间
time_t shm_ctime; 最后修改时间
pid_t shm_cpid; 创建者进程ID
pid_t shm_lpid; 最后映射/取消映射的进程ID
shmatt_t shm_nattch; 映射的次数
};
struct ipc_perm {
key_t __key; IPC键值
uid_t uid; 有效用户ID
gid_t gid; 有效组ID
uid_t cuid; 创建者的用户ID
gid_t cgid; 创建者的组ID
unsigned short mode; 权限
unsigned short __seq; IPC标识
};

五、消息队列

消息队列就是由内核负责管理的一个管道,可以按顺序发送消息包(消息类型+消息内容),可以全双工工作,可以不按消息的顺序接收消息。
int msgget(key_t key, int msgflg);
功能:创建/获取消息队列
key:IPC键值,由ftok函数自动生成
msgflg:
0 获取消息队列
IPC_CREAT 创建消息队列
IPC_EXCL 如果存在则创建失败
返回值:消息队列标识
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:向消息队列发送消息
msqid:消息队列标识,msgget函数的返回值
msgp:结构指针
struct msgbuf {
long mtype; //消息类型
char mtext[n]; //消息内容
};
msgsz:消息的长度,不包括消息类型,sizeof(msgbuf)-4。
msgflg:
0 阻塞,当消息队列满时,等待。
IPC_NOWAIT 不阻塞,当消息队列满时,不等待。
返回值:成功发送返回0,失败返回-1。
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
功能:从消息队列中按类型获取消息
msqid:消息队列标识,msgget函数的返回值
msgp:
struct msgbuf {
long mtype; //消息类型
char mtext[n]; //消息内容
};
msgsz:要接收一消息的长度,可以长一些。
msgtyp:要接收的消息类型
0 接收任意类型的消息(接收队列中第一个消息)。
>0 只接收msgtyp类型的消息
<0 接收消息队列中小于等于msgtyp绝对值的消息,取小的那个。
msgflg:
0 阻塞,消息队列中是否有对应类型的消息,没有则等待。
1 不阻塞,消息队列中没有对应类型的消息,则返回。
----------------------------------------
MSG_NOERROR:
消息类型正确,而消息的实际长度大于msgsz,则不接收消息并返回-1。
如果msgflg带MSG_NOERROR标志,则把多余的消息截取,成功接收。
IPC_NOWAIT:如果消息队列没有要接收的消息,则不等待,返回-1。
MSG_EXCEPT:接收消息队列中第一个消息类型不是msgtyp的消息,编译时添加-D_GNU_SOURCE参数。
返回值:成功接收到消息的字节数

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
功能:删除消息队列,设置或获取消息队列属性
msqid:消息队列标识,msgget函数的返回值
cmd:
IPC_STAT 获取消息队列的属性
IPC_SET 设置消息队列的的属性
IPC_RMID 删除消息队列
返回值:成功返回0,失败返回-1。

struct msqid_ds {
struct ipc_perm msg_perm; // 权限
time_t msg_stime; // 最后一个消息发送时间
time_t msg_rtime; // 最后一次消息接收时间
time_t msg_ctime; // 最后一次修改时间
unsigned long __msg_cbytes; // 消息队列中的字节数
msgqnum_t msg_qnum; // 消息队列中消息的个数
msglen_t msg_qbytes; // 消息队列中容纳的最大字节数
pid_t msg_lspid; // 最后一次发送消息进程
pid_t msg_lrpid; // 最后一次接收消息进程

六、信号量

内核维护的计数器,用于管理多进程共享资源。
例如:有个变量N表示资源的数量,当有进程想要独占一份资源时
n的值要-1(可能减多个) 如果n的值等于0(不够减),进程阻塞,直到n的值
可以减再被还行,当资源使用完毕后n要+1(可能加多个)
int semget(key_t key, int nsems, int semflg);
功能:创建/获取信号量
key:IPC键值
nsems:信号量的数量
semflg:
0 获取信号量
IPC_CREAT 创建信号量 存在则获取,不存在则创建
IPC_EXCL 存在则创建失败
返回值:信号量标识
int semop(int semid, struct sembuf *sops, unsigned nsops);
semid:信号量标识
sops:结构体数组
nsops:数组的长度
功能:操作信号量
struct sembuf
{
unsigned short sem_num;信号量的下标
short sem_op; 操作
short sem_flg;标记
}
IPC_NOWAIT 当信号量不够减时,不阻塞
SEM_UNDO 进程结束时,信号量的值自动归还

int semtimedop(int semid, struct sembuf *sops, unsigned nsops,
struct timespec timeout);
功能:带时间限制的操作信号量
timespec
{
__time_t tv_sec 秒
long int tv_nsev 纳秒
}
int semctl(int semid, int semnum, int cmd, …);
功能:删除信号量,获取设置信号量的属性,初始化信号量的值
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) */
};
cmd:
IPC_STAT:获取信号量的属性
IPC_SET :设置信号量的属性
IPC_RMID: 删除信号量
IPC_INFO: 获取信号量的信息
SEM_INFO: 设置信号量的信息
SEM_STAT: 设置信号量的属性
GETALL: 获取所有信号量的值
GETNCNT: 获取信号量的数量
GETVAL: 获取信号量的值
SETALL: 设置所有信号量的值
SETVAL: 设置某个信号量的值
struct ipc_perm {
key_t __key;
uid_t uid;
gid_t gid;
uid_t cuid;
gid_t cgid;
unsigned short mode;
unsigned short __seq;
};

struct seminfo {
int semmap;
int semmni;
int semmns;
int semmnu;
int semmsl;
int semopm;
int semume;
int semusz;
int semvmx;
int semaem;
};

编程模型:
进程A 进程B
创建信号量 semget 获取信号量
初始化信号量的值 semctl …
加减信号量 semop 加减信号量
删除信号量 semctl …
注意:信号量仅仅是计数,一定要与资源对应
七、IPC命令
显示IPC对象
ipcs -m 共享内存
ipcs -q 消息队列
ipcs -s 信息量
ipcs -a
删除 ipc对象
ipcrm -m ID
ipcrm -q ID
ipcrm -s ID

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值