一、信号量
1.定义:用来进程同步的特殊变量,一个特殊计数器。
大于0时,记录资源的数量,而且进程可以获取资源并利用;
小于0时,记录等待资源的进程的数量,进程必须阻塞等待有其他进程释放资源。
大于1时,称之为信号量计数器。
信号量集:多个信号量的集合 ——>内核维护的一般是一个信号量集。
内核对象:key 用户标识 ID 内核标识
2.相关操作
- PV操作:
P:信号量的值-1;获取临界资源时,如果当前资源不可用(信号量值为0), P在占据资源前会阻塞;
V:信号量的值+1;释放占用的临界资源 ;
- 创建获取信号量集合的内核对象
如果是创建,必须对信号量初始化(设置初始值), 若是获取,不能对信号量初始化
int semget((key_t)key,int semes,int flag);
semes:创建信号量集时,执行创建的信号量集中信号量的个数;
flag:指定操作方式:IPC_CREAT; 指定操作权限:文件权限的方式
返回值:失败返回-1,成功返回信号量集内核标识ID。
- 对信号量初始化
int secmctl(int semid,int semnum,int cmd,....);
semid:semget返回的文件描述符;
semnum:下标;
cmd:SETVAL;
union senum
{
int val;
struct semid_ds *buf;
unsigned short *arry;
struct seminfo *_buf;
};
- 访问临界P/V操作
int semop(int semid,struct sembuf *sops,int nsops);
- 应用:
A、B进程交替打印hello(A)、world(B).
父子进程最快的一种IPC,一次交互过程相比于管道和消息队列,少两次数据的拷贝。
二、消息队列
1.定义:
消息: 类型+数据 type:hello 消息都是独立的一条 type world
队列:一种先进先出的结构
2.特点
- 是消息存放的链表。具有特定的格式,存放在内存中,由消息队列标识符标识;
- 消息队列允许一个或多个进程向他写入/读取消息;
- 消息队列可实现消息的随机查询机制,不一定要以先进先出的顺序读取,也可按照类型进行读取;
3.相关操作
- 相关头文件: #include<sys/types.h> #include<sys/ipc.h> #include<sys/mag.h>
- 查看系统上的消息队列:ipcs -q 删除系统上的消息队列:ipcm -q msgid
- 创建: int msgget(key_t key,int msgflag);
key:用户标识,用户程序使用相同的key值就能访问同一个内核对象;
msgflag:指定是否创建内核对象,指定内核对象的访问权限(文件权限);
返回值:如为内核标识/内核ID,进行下一步操作;如果为-1,则创建失败。
- 发送消息: int msgsnd(int msgid,void *msgp,size_t msgsz,int flag);
*msgp为消息:类型 +数据; msgsz:数据的长度
struct mymseg{
long mytype; //消息:类型+数据
char mtext[10];//数据的长度
};
- 接收消息:int msgrcv(int msgid,void *ptr,size_t msgsz,int flag);
- 删除消息队列:int msgctl(int msgid,int cmd,struct msqid_ds *buf) //这种删除立即生效
*** 操作系统对进程间通用的信号量在内核中都是以信号量集管理的。也就是通过semget函数获取到的是信号量集的标识符。其他函数操作时,必须指明操作是哪个信号量集中的哪个信号量。类似数组的下标。
三、共享内存
1.原理:多个进程共享一块物理内存地址,将物理内存地址分别映射在自己的虚拟空间上。10个进程将物理内存地址映射到自己的虚拟地址上,而且这10个进程可相互通信。由于是同一块内存地址,当第一个向这块内存写入数据时,其他进程也会看到。所以进程在使用这块空间时,必须做到同步控制。
2.相关操作
int shmget((key_t)key,int semes,int flag);//size执行共享内存的空间大小,以字节为单位
- 在本进程中分配虚拟地址映射到内核对象指向的共享空间上
void *shmat(int semid,void *addr,int flahg);//默认情况下 addr为NULL,flag为0.
以上两步相当于malloc操作。
- 将本进程中的指针与共享空间断开:
int shmdt(void *adrr);//free();
- 销毁共享内存:
int shmatctl(int cmd,int shmid,struct shmid_ds *buf);
说明:共享内存有一个计数器,如果调用shmat,计数器+1,调用shmat,计数器-1.shmat函数删除,仅仅删除该段的标识符, 而且不能通过shmat来连接该段。
四、管道
具体内容可参考博客:https://blog.csdn.net/rjp_1987/article/details/107514525
附加:
内核(操作系统) 对象 (实体变量) 属性信息 系统调用函数访问对象;
4G的虚拟空间地址 3G的用户空间是独立的 1G的内核空间是用户共享的;
临界资源:同一时间段只能被一个进程访问的资源。
临界区:访问临界资源的代码区域。
原子操作:一旦开始就不能被打断的操作。
同步:当调用函数时,阻塞等待条件发生,在访问临界资源时,多进程按照一定顺序执行。
异步:当调用函数时,无论条件是否发生,函数会立刻返回,当条件发生后需要依赖系统的消息。通过通知机制,通知调用此 函数的进程。
阻塞与非阻塞关注的是进程调用函数的状态。