一、进程间的通信
1.共享内存
(一)引入和概念
概念:多个进程申请同一块内存区域用于通信
shell命令:
查看共享内存
ipcs -m
删除共享内存
ipcrm -m 共享内存的id
(二)相关的接口函数
(1) 申请共享内存
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
返回值:成功 返回共享内存的id号
失败 -1
参数:key --- 键值
size --- 你要申请的共享内存的大小,单位是字节(512字节的整数倍)
shmflg --- IPC_CREAT IPC_EXCL 0777
类似于O_CREAT O_EXCL
key有两种写法:
写法一:程序员随便写一个无符号正整数即可
写法二:调用系统提供的专门生成key值的函数ftok()
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
返回值: 根据你传递的路径和整数计算一个独一无二的键值
参数:pathname --- 任意一个linux系统中的合法路径
proj_id --- 任意一个整数
(2) 映射得到共享内存的首地址
#include <sys/ipc.h>
void *shmat(int shmid, const void *shmaddr, int shmflg); //类似于mmap()
返回值:成功 映射得到的共享内存的首地址
失败 NULL
参数:shmid --- 共享内存的id,shmget的返回值
shmaddr --- 默认设置为NULL,表示由操作系统自动给我分配共享内存
shmflg --- 设置为0,表示共享内存是可读可写的
(3) 解除映射
#include <sys/ipc.h>
int shmdt(const void *shmaddr);
参数:shmaddr --- 你刚才映射得到的首地址
(4) 多功能函数,删除共享内存(获取,设置共享内存的属性)
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数:shmid --- 共享内存的id,shmget的返回值
cmd --- IPC_STAT 获取共享内存的属性信息
IPC_SET 设置共享内存的属性信息
IPC_RMID 删除共享内存
struct shmid_ds --- 用来存放获取,设置的共享内存属性
{
shm_perm; //存放权限
shm_segsz; //存放大小
}
2.消息队列
(一) 引入
最大的特点:可以选择性地读取消息队列中的内容
共享内存,消息队列,信号量三种通信方式合称 --- SYSTEM-V IPC通信(内部进程通信)
shell命令:
查看消息队列
ipcs -q
删除消息队列
ipcrm -q 消息队列的id
特点:
①在读取消息队列中内容的时候可以选择性地读取(根据消息的类型来读取)
②如果消息队列中消息的类型一样,接收的时候只能按照发送的先后顺序去接收(跟队列的特点就一致了)
③如果接收的消息类型没有,会导致接收阻塞
④如果消息队列不删除,接收信息的时候,那么没有接收的信息依然在队列中存放着
(二)相关的接口函数
(1) 申请消息队列
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
返回值:成功返回消息队列的id
失败 -1
参数:key --- 键值
shmflg --- IPC_CREAT IPC_EXCL 0777
类似于O_CREAT O_EXCL
(2) 使用消息队列
发送信息到消息队列中
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数:msqid --- 消息队列的id号
msgp --- 发送的内容
msgsz--- 发送多少字节的数据
msgflg--- 设置0
msgp要发送的内容需要封装成一个结构体
struct 名字
{
long msgtype; //标记消息的类型
char msg[20]; //真实的信息
};
从消息队列中接收信息
#include <sys/msg.h>
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数:msqid --- 消息队列的id号
msgp --- 接受的内容
msgsz--- 接受多少字节的数据
msgtyp(重点,重点) --- 消息的类型
msgflg--- 设置0
(3) 删除消息队列,获取修改消息队列的属性
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数:msqid --- 消息队列的id号
cmd --- IPC_STAT 获取消息队列的属性信息
IPC_SET --- 设置消息队列的属性信息
IPC_RMID --- 删除消息队列
struct msqid_ds --- 存放你获取或者设置的消息队列的属性
{
属性;
}
3.信号量
(一)引入和概念
概念:信号量用来协调多个进程对于共享资源的访问(保证每一次只有一个进程在访问共享资源)
手段:阻塞别人,成就自己或者阻塞自己,成就别人
特点:
①如果信号量值为0,你还要做减法操作(p操作),会阻塞当前进程
②信号量的值是不可能为负数的,做减法的时候,如果超过信号量的大小会阻塞当前进程
③信号量做加法运算(v操作)是不会阻塞当前进程的
(二)相关的接口函数
(1)申请信号量
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
参数:key --- 键值
nsems(重点) --- 你打算申请多少个信号量(申请多少张积分卡),信号量的编号从0开始
例如:semget(5415,2,IPC_CREAT|IPC_EXCL|0777); //我申请了两张卡,编号分别0,1
semflg --- IPC_CREAT IPC_EXCL 0777
类似于O_CREAT O_EXCL
(2)操作使用信号量(重点,重点,重点)
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, size_t nsops);
参数:semid --- 信号量的id号
struct sembuf(重点)
{
sem_num; //你要操作信号量的编号,默认从0开始
sem_op; //你想对积分卡进程的操作
加法操作---- V操作
减法操作---- P操作
sem_flg; //默认设置为 SEM_UNDO,先不管
}
nsops --- struct sembuf结构体的个数,一般设置为1
(3) 信号量赋值,获取信号量的值
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ...);
参数:semid --- 信号量的id号
semnum --- 信号量的序号
cmd --- GETVAL 获取信号量的值
SETVAL 设置信号量的值
IPC_STAT 获取信号量的属性
IPC_SET 设置信号量的属性
IPC_RMID 删除信号量
第一个功能:设置信号量的值
semctl(semid,0, SETVAL,1); //我想把第一个信号量(序号是0)的值设置为1
第二个功能:获取信号量的值
int ret=semctl(semid,0,GETVAL); //我想获取第一个信号量的值,返回值就是第一个信号量的值
第三个功能:删除信号量
semctl(semid,0,IPC_RMID);//删除第一个信号量
二、进程的生老病死
1. 进程的几种状态
就绪态: 进程运行了,但是还没有获得cpu的执行权,这种状态就叫做就绪态
执行态: cpu通过内核的调度算法切换到当前进程,当前进程立马取得了cpu执行权,运行起来
睡眠态、挂起态: 代码中sleep() pause()
暂停态: 外界给进程发送STOP信号,进程就立马进入暂停态
僵尸态: 进程退出了,如果没有父进程回收,就变成僵尸进程
死亡态: 进程退出了,父进程也回收了