System V IPC
IPC
objects
消息队列(message queue)
旗语(信号量)(semaphore
set)
共享内存(shared memory)
shell命令
ipcs, ipcrm
创建System V IPC时访问授权
S_I RUSR
用户读
S_I WUSR
用户写
S_I RGRP
组读
S_I WGRP
组写
S_I ROTH
其它人读
S_I WOTH
其它人写
创建System V IPC时指令
IPC_CREAT
key不存在则创建
IPC_
EXCL
key存在则失败
IPC_NOWAIT
请求的IPC须等待则出错
#include
key_t
ftok(char * fname, int id)
系统建立IPC通信必须指定一个ID值。通常情况下,该id值通过ftok函数得到。
fname为指定的文件名(该文件必须是存在而且可以访问的), id是子序号,虽然为int,但是只有8个比特被使用(0- 2 55)。当成功执行的时候,一个key_t值将会被返回,否则返回-1。
在一般的UNI X实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。如指定文件的索引节点号为65538,换算成16进制为0x0 10002,而你指定的ID值为3 8,换算成16进制为0x26,则最后的key_t返回值为0x26010002。
查询文件索引节点号的方法是:ls -i
设置System V IPC时的控制命令
IPC_RMID
删除标识符指示的IPC量
IPC_SET
设置选项
IPC_STAT
读取选项
ipc_perm结构
struct ipc-perm
{
Uid_t
uid;//Owner’s
user ID
Gid_t
gid;// Owner’s group ID
Uid_t
cuid;//Creator’s user ID
Gid_t
cgid;//Creator’s group ID
Mode_t mode;//read/write permission
Key_t key ;
Unsigned short seq ;
}
System V IPC函数概览
功能
消息队列
信号量
共享内存
分配一个IPC对象,获得对IPC的访问
msgget
semget
shmget
IPC操作:发送/接收消息,信号量操作,连接/释放共享内存
msgsnd/msgrcv
semop
shmat/shmdt
IPC控制:获得/修改状态信息,取消IPC
msgctl
semctl
shmctl
消息队列IPC
消息队列就是消息的一个链表,它允许一个或多个进程向它写消息,一个或多个进程从中读消息。这些消息存在于内核中,由“队列ID”来标识。
消息队列的实现包括创建和打开队列、添加消息、读取消息和控制消息队列这四种操作
#include
#include
#include
int
msgget(key_t key, int msgflg) ;
功能:创建一个新的消息队列,或者希望获取一个已经存在的消息队列(msgflg = 0)。
返回值:成功返回消息队列标识符;失败返回-1。
参数:
key:消息队列键值/名字。
msgflg:指令和访问权限标志,包括:IPC_CREAT如果内核中没有此队列,则创建它。IPC_
EXCL当和IPC_CREAT一起使用时,如果队列已经存在,则失败。打开权限类似open(),相当于文件的访问权限。
#include
#include
#include
int
msgsnd ( int msgid, struct msg buf *msgp, int msgsz, int msgflg ) ;
功能:往队列中发送一条消息。
返回值:成功返回0,错误返回-1。
参数:
msgid:是消息队列标识符,它是由系统调用msgget返回的.
msgp:是指向消息缓冲区的指针.
msgsz:中包含的是消息的字节大小,但不包括消息类型的长度(4个字节).
msgflg:可以设置为0(此时为忽略此参数),或者使用IPC_NOWAIT.
如果消息队列已满,那么此消息则不会写入到消息队列中,控制将返回到调用进程中.如果没有指明,调用进程将会挂起,直到消息可以写入到队列中
#include
#include
#include
int msgrc v (int msgid, struct msg
buf *msgp, int msgsz, long mtype, int msgflg) ;
功能:读取消息,从消息队列中取走消息。
返回值:成功返回0,错误返回-1。
参数:
msgid:用来指定将要读取消息的队列
msgp:代表要存储消息的消息缓冲区的地址.
msgsz:是消息缓冲区的长度,不包括mtype的长度,它可以按照如下的方法计算:msgsz = sizeof(struct mymsgbuf)- sizeof(long) ;
mtype:是要从消息队列中读取的消息的类型.如果此参数的值为0,那么队列中最长时间的一条消息将返回,而不论其类型是什么.
msgflg:没有消息可接收时,如果该参数中IPC_NOWAIT被设置,那么立刻返回-1;IPC_NOWAIT被清除则挂起。
#include
#include
#include
int msgctl ( int msgid, int cmd, struct
msqid_ds *buf ) ;
功能:对消息队列的操作。
返回值:成功返回0,错误返回-1。
参数:
msgid:消息队列ID .
cmd: IPC_RMID从系统内核中移走消息队列, IPC_STAT读取消息队列当前设置, IPC_SET修改消息队列的设置。
buf :队列状态数据结构。
旗语同步
旗语是一个受保护的变量,它可以提供对两个以上进程共享资源限制访问的方法。旗语允许两个操作,称为获取与释放。获取操作允许进程取得旗语,如果旗语已被其它进程获取,则阻塞直到旗语可用为止,进程使用完旗语后需释放旗语,以使其它进程可获取它。释放旗语会自动唤醒下一个等待获取旗语的进程。
旗语由Edsger Di j kstra为T.H.E.操作系统引入的。最初被定义为P和V。P是荷兰语proberen(尝试), V是verhogen(增加)。
旗语分为两种基本类型。第一种是二进制旗语,二进制旗语代表单个资源;第二种是计数旗语,用来代表数量大于一的共享资源。
#include
int
semget(key_t key, int nsems, int semflg) ;
功能:创建一个新的旗语或取得一个已有的旗语。
返回值:成功返回旗语标识符,失败返回-1。
参数:
key:系统范围内的唯一标识符,其它进程访问旗语的依据。
IPC_P
RIVA T E告诉semget自己生成标识符,所以其它进程无法访
问该旗语。使用ftok()函数获得唯一标识。
nsems:旗语个数,为1时表示单个旗语,大于1表示旗语数组
,用来获取已有旗语时设为0
semflg:指令和访问权限标志,
IPC_C
REAT创建新的旗语,IPC_C REAT|IPC_EXCL如果旗语存
在则失败,errno设为EEXIST。
semflg
=0用来获取一个已有的旗语。
打开权限类似open(),相当于文件的访问权限。
#include
int
semop(int semid, struct sem buf *sops, size_t nsops);
功能:提供获取和释放旗语或旗语数组的方法。
返回值:成功返回0,否则-1。
参数:
semid:旗语描述符。
sops:旗语结构(数组)指针,包含了具体操作。
struct
sembuf {
unsigned
short sem_num ; //对应旗语数组中的旗语,0对应第一个旗语
short sem_op ;//旗语的当前值记录相应资源目前可用数目;sem_op >0进程要释放sem_op数目的共享资源;sem_op=0用于对共享资源是否已用完的测试(调用进程将调用sleep(),直到信号量的值为0);sem_op
<0进程要申请-sem_op个共享资源
short sem_flg ;//IPC_NOWAIT:无旗语可用则失败,SEM_UNDO:在进程结束时,相应的操作将被取消,如果设置了该标志位,在进程没有释放共享资源就退出时,内核将代为释放。
};
#include
int semctl(int semid, int semnum, int cmd, …);
功能:控制旗语信息。
返回值:成功返回0(或要获取的值),否则-1。
参数:
semid:旗语标识符。
semnum:旗语编号。
cmd:要进行的操作。
第四个参数,是union semun的实例,具体值依赖cmd。
union semun {
int val;
struct semid_ds *buf ;
unsigned short *array;
} arg;
cmd命令(设第四个参数为arg) :
IPC_STAT获取旗语信息,信息由arg.buf返回;
IPC_SET设置旗语信息,待设置信息保存在arg.buf中;
IPC_RMID删除旗语或旗语数组;
GETALL返回所有旗语的值,结果保存在arg .array中,参数sennum被忽略;
GETNCNT返回等待semnum所代表旗语的值增加的进程数,相当于目前有多少进程在等待semnum代表的旗语所代表的共享资源;
GETPID返回最后一个对semnum所代表旗语执行semop操作的进程ID;
GETV A L返回semnum所代表旗语的值;
GET ZCNT返回等待semnum所代表旗语的值变成0的进程数;
SETA LL通过arg.array更新所有旗语的值;同时更新与本旗语集相关的semid_ds结构的sem_ctime成员;
SETVA L设置semnum所代表旗语的值为arg.val;
共享内存编程
共享内存区域是被多个进程共享的一部分物理内存。如果多个进程都把该内存区域映射到自己的虚拟地址空间,则这些进程就都可以直接访问该共享内存区域,从而可以通过该区域进行通信。
共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容。
不提供任何同步功能
#include
int shmget(key_t key, size_t size, int
shmflg) ;
功能:创建共享内存或获取一个已经存在的共享内存(shmflg =0)。
返回值:成功返回共享内存标识符,失败返回-1。
参数:
key:标识共享内存的键值。(IPC_PRIVATE, ftok())
siz e:要建立共享内存的长度(打开已有共享内存时置0)。(n* P AG E_SI ZE)
shmflg:指令和访问权限标志。
IPC_C REAT如果共享内存不存在,则创建一个共享内存,否则打开操作。
IPC_EX CL只有在共享内存不存在的时候,新的共享内存才建立,否则就产生错误。
打开权限类似open(),相当于文件的访问权限。
#include
int *shmat(int shmid, const void *shmaddr,
int shmflg) ;
功能:允许进程访问一块共享内存(共享内存刚创建时不能使用)。
返回值:成功返回共享内存的起始地址,失败返回-1。
参数:
shmid:共享内存的标识符。
shmaddr:共享内存的起始地址
shmflag:本进程对该内存的操作模式。如果是SHM_ RDONLY的话,就是只读模式。
#include
int shmdt(const v oid *shmaddr) ;
功能:释放共享内存。
返回值:成功时返回0。失败时返回-1。
参数:
shmaddr是共享内存的起始地址。
#include
int shmctl(int shmid, int cmd, struct
shmid_ds *buf);
功能:共享内存控制函数。
返回值:成功返回0,失败返回-1。
参数:
shmid:共享内存的ID。
cmd:允许的操作, 最常用的包括:
IPC_ RMID删除共享内存段。
buf:保存内存模式状态和访问权限的数据结构,通常为0。