分类: LINUX
2012-04-28 10:43:13
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。