回顾:
信号:信号集、信号屏蔽sigprocmask()、sigaction()是signal()增强版,如果需要对信号本身有更多的了解,可以使用sigaction()。结构sigaction中配置sa_flags为SA_SIGINFO,并使用sa_sigaction作为处理函数的指针。
siqueue()和计时器
IPC: IPC原理 两个进程通过一个媒介 完成数据交互。
管道: 有名管道 无名管道
用mkfifo创建管道文件 进行通信。
无名管道主要用于fork()创建的父子进程之间的通信。
今天:
无名管道 用pipe()提供内核的管道文件和读写通道。
XSI IPC(重点)
共享内存、消息队列和信号量集 都属于XSI IPC规范,因此在用法上有很多共同点。
共享内存的媒介是 一块内核管理的内存,多个进程映射到这块内存上读写数据,完成数据交互。共享内存 效率高,但多进程同时写入时,数据会被互相 覆盖。
XSI的共同点:
1 共享内存、消息队列和信号量集都是Linux/Unix的内核对象,重启机器不会消失。程序创建了XSI IPC之后,如果不再使用,一定要在程序中删除。
2 使用方式的共同点
2.1 创建/获取 都需要一个外部key和内部ID。用key可以得到内部ID,内部ID对应 内核中的IPC结构。
2.2 key的生成有三种方式:
宏IPC_PRIVATE 直接做key,这种方式基本不用,因为这种方式只能创建不能获取。
定义一个通用的头文件,把所有的key定义在头文件中,key其实就是一个整数。
函数ftok()负责生成key:
key_t key = ftok(path,projectid);
path 是一个必须真实存在的路径,projectid随便给一个恩就行,不要重复,范围0-255.
如果path和projectid相同,key的值就相同。
2.3 用key创建/获取ID
XSI IPC都有一个 xxxget() 获取/创建 内部ID。
int shmid = shmget();
int msgid = msgget();
2.4 创建IPC结构时,都需要提供一个参数flags,一般为
IPC_CREAT|IPC_EXCL|0660 (和O_ 类似)
IPC_EXCL 如果结构已经存在,返回-1 出错。
2.5 对IPC结构都提供一个 操作函数xxxctl(),包含:
IPC_STAT : 获取IPC结构的相关属性
IPC_SET : 修改IPC结构的相关属性(能改的很少)
IPC_RMID : 按照ID 删除IPC结构
比如:shmctl() msgctl()
IPC相关命令:
ipcs 查看当前内核中的ipc结构
-a 所有
-m 共享内存
-q 消息队列
-s 信号量集
ipcrm 删除当前内核中的ipc结构
ipcrm -m ID 按ID删除
共享内存的使用步骤:
1 使用ftok()创建一个外部key(包含头文件也行)。
2 使用shmget()创建/获取共享内存的内部ID。
3 使用shmat()挂接共享内存(映射),返回 首地址
4 正常使用 首地址(或读或写)
5 使用shmdt()脱接共享内部(解除映射)
6 如果所有进程都不再使用,使用shmctl()删除共享内存
注:ftok的参数projectid 必须非0.
当使用删除命令/函数 删除共享内存时,不确保立即删除。只是给 共享内存做一个删除标记,当 挂接进程数为0 才能真正删除。nattch 就是挂接进程数。
shmctl()包括: 查询共享内存的属性、修改共享内存的属性、删除共享内存。
XSI IPC应用最多的是 消息队列。
可以把数据 封入消息中,然后 再把消息 放入队列中。内核创建和管理队列,进程把 数据封入消息 在放入队列或从队列中取出消息。
消息队列的使用步骤:
1 使用ftok() 得到key。
2 使用msgget()用key 创建/获取 内部ID。
3 使用函数 msgsnd() msgrcv()放入或取出消息(队列中)
4 如果不再使用消息队列,msgctl()删除队列。
消息分为有类型消息和无类型消息,无类型消息可以是任意类型的数据,比如:字符串、整数、浮点。
有类型消息,类型是预先设定的结构体,而且结构:
struct 任意名字{
long mtype; //第一个成员必须 消息的类型
char msg[100];//第二个成员 随意 消息的数据
};
消息类型可以让 不同的进程 拿到自己的消息,而不用考虑谁先谁后。消息类型必须是大于0的整数,0代表 任意类型。
msgsnd(msgid,&msg,sizeof(msg),0/*IPC_NOWAIT*/)
0 代表如果队列满了阻塞
IPC_NOWAIT代表如果队列满了直接返回错误
注:在发送时,计算sizeof 不包括消息类型(包括了也没错)
msgrcv(msgid,&msg,sizeof(msg),msgtype,
0/*IPC_NOWAIT*/)
注:发送时size如果不包括消息类型,接收时也不要包括
msgtype 设定接收消息的类型,包括:
== 0 接收任意类型的消息,典型的先入先出
> 0 接收对应类型的消息
< 0 接收 小于等于 msgtype绝对值的 最小类型消息
(类型 从小到大)
作业: 为综合案例 模拟实现银行ATM功能
1 思考:银行ATM的基本功能,界面
2 复习以下知识点:
消息队列、多进程、信号signal()、文件的基本操作
安排:
1 助教老师 系统分析
2 自己思考/动手,如有问题 多问。
3 周四上午 讲师讲解