day10

来源:互联网 发布:阿里云备案域名 编辑:程序博客网 时间:2024/04/29 10:33
XSI IPC之共享内存和消息队列(有固定的套路)
共享内存/消息队列/信号量集   遵循相同的规范,因此在编程上有很多共性的东西。


共同点:
1.XSI IPC都是系统内核管理的,叫内核结构。
2.XSI IPC都由外部的key ,类型是key_t,可以定位IPC结构。
3.外部key的获取方式有三种:
3.1 宏IPC_PRIVATE 做key,这种方式程序员基本上不用,因能建IPC结构,但外部不能获取
3.2 定义一个共同体的头文件,所有的key存在头文件中,(key的赋值需要单独定义一个.c文件)
3.3 使用函数 ftok() 生成key.ftok()以文件作为参数,这个文件/目录是必须存在的
4 在内核中的IPC结构都有一个ID代表,这个ID可以用函数获取,这个函数叫:xxxget(key,……)比如:
shmget(key,……)   msgget(key,……)
5创建IPC结构的函数也是 xxxget(),其中的flag需要写成:IPC_CREAT|0666(权限)
6在代码中,用ID代表IPC结构,就像fd代表一个打开的文件一样。
7每种IPC结构都提供了一个xxxctl()函数,可以实现对IPC结构的查询/修改和删除,比如:shmctl()  msgctl()  
其中,会有一个cmd参数,至少包括三个值:
IPC_STAT -查询
IPC_SET  -修改
IPC_RMID  -删除


8.系统提供了一套命令查看/删除IPC结构
ipcs -查看IPC结构
ipcs -a 查看所有IPC结构,包括3个
ipcs -m 查看共享内存
ipcs -q 查看队列
ipcs -s 查看信号量集




ipcrm -删除IPC结构,按ID 删除
ipcrm -m ID删除共享内存
ipcrm -q ID 删除消息队列
ipcrm -s ID删除信号量集


共享内存(shared memory)
共享内存的媒介是一块系统内核管理的物理内存,这块物理内存允许所有进程挂接(映射),多个进程就直接映射到同一块物理内存,数据可以直接交互,使用完毕后脱接共享内存(解除映射)。
共享内是IPC中最快的。
共享内存的使用步骤:(固定套路)
1.获取key ,获取函数ftok()或写共用的头文件。
key_t key=ftok();
2 创建/获取共享内存的内部ID,使用函数shmget()
3挂接共享内存(映射),使用函数shmat().
4正常使用共享内存(存取数据)
5脱接共享内存(解除映射),使用函数shmdt()
6如果确保不再使用,可以使用shmctl(IPC_RMID)删除


key_t  ftok(char* path,int projectid)
path 就是文件/目录的路径,必须存在,否则出错
projectid是项目ID,0-255(只取后8位二进制)


int shmctrl(int shmid,int cmd,struct shmid_ds* ds)
功能:查询/修改/删除 共享内存
参数:shmid就是共享内存的内部ID
cmd 就是操作方式,包括:
查询 IPC_STAT/修改IPC_SET/删除IPC_RMID
ds只对查询和修改有效,删除时传0即可。
返回:成功返回的比较复杂,和cmd有关,失败返回-1.


删除共享内存时,不一定会立即删除,只有nattch为0的共享内存才能删除,如果nattch不为0,只会做一个删除标记而不会立即删除,当nattch为0时才能删除。
共享内存的优点就是太快,缺点不能很好的处理多个进程同时写数据的情况。多个进程同时写数据的时候采用消息队列。


消息队列 -队列是种数据结构,按次序存放元素,先入先出
队列中的元素就是消息。
消息队列的使用方式就是先把数据放入消息中,然后把消息放入队列中。队列的管理由内核完成。


消息队列就是以内核管理的一个队列作为交互的媒介。比较常用的IPC。(重点)
消息队列的使用步骤:
1.使用ftok()或共用的头文件提供一个key;
2使用msgget(key,……)创建/获取一个消息队列
3使用msgsnd()发送消息(把消息放入队列中)或使用msgrcv()取出消息(把消息从队列中取出)
4如果确保不再使用消息队列,可以使用msgctl(IPC_RMID)删除


消息分为 有泪新和无类型消息,无类型消息可以支持任意类型的数据,但只能先入先出,如果放入的顺序和取出的次序不同,一定会出问题,更多的时候使用有类型小型。
有类型消息必须是一个结构体,
struct 名称{//名称  程序员随便起,合法标识符就行
long mtype;//第一个必须long,代表消息类型
    数组或结构;//数据区,数据放在这里
}
其中,mtype必须大于0.


int msgsnd(int msgid,void* msgp,size_t msgsz,int flags)
功能:发送消息到消息队列的末尾。
参数:msgid就是消息队列的ID
msgp 就是消息结构体的首地址
msgsz 就是消息结构体中数据的大小(不带类型玩)
flags取0 或IPC_NOWAIT 0就是满了会等,IPC_NOWAIT满了就直接返回-1
返回 :成功返回0,失败返回-1
ssize_t msgrcv(int msgid,void* msgp,size_t msgsz.long msgtype,int flags)
功能:按类型接受
参数:msgid/msgp/msgsz/flags和msgsnd一样
msgtype  可以取三种值
>0  就是接受特定类型的消息(类型=msgtype)
0  就是接受任意类型的消息(先入先出)
<0  就是接受类型小于等于|msgtype|的消息,从小到大顺序:比如:msgtype传了-3   ,接受消息的类型为1 2 3
返回:失败返回-1,成功返回实际接受的字节数。


作业:
1.下周一综合案例,需要用到的知识点:文件读写/进程管理
信号/消息队列。回去好好的看一下。
2.如何删除消息队列?
思路:创建的进程应该负责删除,创建的进程while(1)保证不退出,用完后借助信号 ctrl+c退出,在退出的同时(信号处理函数中)删除掉消息队列。









































0 0
原创粉丝点击