进程间的通信之共享内存、消息队列和信号量(系统编程三)

18 篇文章 0 订阅
16 篇文章 0 订阅

一、进程间的通信

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信号,进程就立马进入暂停态

僵尸态: 进程退出了,如果没有父进程回收,就变成僵尸进程

死亡态: 进程退出了,父进程也回收了

2.进程状态转换

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java.L

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值