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。