System V IPC

来源:互联网 发布:js 全部替换 编辑:程序博客网 时间:2024/06/12 09:07

        Linux/Unix下进程间通信有3类:

        1.  传统Linux/Unix进程间通信:管道(有名管道、无名管道)、信号。

        2.  SystemV IPC:共享内存、消息队列、信号灯。

       3.  套接字(socket):可以实现不同计算机间的进程通信,即可实现网络通信。

一、共享内存。

       共享内存是多个进程共享一个物理内存,一个进程从共享内存里写,另一个内存就可以立马从共享内存中读,所以共享内存是进程间通信最快的一种方式。

       实现共享内存有两个步骤:

     1.  创建共享内存;

    2.  映射共享内存,即将这片共享内存映射到需要共享该内存空间的进程中去。

 

创建进程:

intshmget(key_t key,int size,int shmflg00)

       key是标识共享内存的键值:0/IPC_PRIVATE。当key为IPC_PRIVATE时,函数只创建一片共享内存。当指定其他键值时就可以使用shmget()创建多片共享内存。而key我们也可以通过ftok()这个函数获得。函数原型为:key_t ftok(const char*fname,int id);fname就是需要指定的文件名,可以为当前文件夹,即为./。

#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>int main(){int shmid;key_t key;key=ftok(".",'a');if((shmid=shmget(key,4096,IPC_CREAT|0666))<0){perror("shmget");exit(1);}printf("shared memory id=%d\n",shmid);exit(0);}

 

共享内存映射:

intshmat(int shmid,char *shmaddr,int flag)

shmid:shmget()返回的共享内存标识符;

flag:决定采用什么方式来确

shmaddr:如果shmaddr为0,即用户没有指定该共享内存区域在它的虚拟空间中的位置,则由系统在进程的虚拟地址空间中为其找一块区域(从1G开始);否则,就用shmaddr作为映射的虚拟地址。定地址映射,通常为0;

#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#include <stdio.h>#include <stdlib.h>int main(int argc,char *argv[]){char *p;int shmid=atoi(argv[1]);p=shmat(shmid,NULL,0);printf("p=%p\n",p);sprintf(p,"hello world\n");shmdt(p);exit(0);}

 

    解除地址映射:

    int shmdt(char *shmaddr)

#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#include <stdio.h>#include <stdlib.h>int main(int argc,char *argv[]){char *p;int shmid=atoi(argv[1]);p=shmat(shmid,NULL,0);printf("p=%p\n",p);printf(p);shmdt(p);exit(0);}

 

        二、消息队列

        消息队列存放在内核中并由消息队列标识符标识。每个消息包含一个正长整型类型字段,一个非负长度以及实际数据字节(对应于长度),所有这些都在将消息添加到队列时,传送给msgsnd。msgrcv用于从队列中取消息。对于该类型的消息队列来说,它不是一个先进先出的队列,可以按消息的类型字段取消息,POSIX消息队列则不能按照消息类型字段提取消息。
    int msgget(key_t key, int flag)

返回:若成功则为消息队列 ID,若出错则为-1。

intmsgsnd(int msqid, const void *ptr, size_t nbytes, int flag);返回:若成功则为 0,若出错则为 -1

intmsgrcv(int msqid, void *ptr, size_t nbytes, long type, int flag) ;返回:若成功则为消息数据部分的长度,若出错则为 -1

        1.mesgget用于创建一个新队列或打开一个现存的队列,当创建一个新队列时,初始化 msqid-ds结构的下列成员:

ipc-perm结构。该结构中 mode按flag中的相应许可权位设置。

msg_qnum,msg_lspid、msg_lrpid、msg_stime和msg_rtime都设置为0。

msg_ctime设置为当前时间。

msg_qbytes设置为系统限制值。

若执行成功,则返回非负队列ID。此后,此值就可被用于其他三个消息队列函数。

       2.msgsnd用于将数据放到消息队列上。每个消息都由三部分组成,它们是:正长整型类型字段、非负长度(nbytes)以及实际数据字节(对应于长度)。消息总是放在队列尾端。

ptr指向一个长整型数,它包含了正整型消息类型,在其后立即跟随了消息数据。它指向的数据结构类似如下的定义,数据结构并不一定要如此定义,只要满足一个长整形后边跟随了消息数据的要求即可,nbytes给出了跟在长整形后边的消息部分的长度flag的值可以指定为IPC_NOWAIT。这类似于文件 I/O的非阻塞 I/O标志。若消息队列已满(或者是队列中的消息总数等于系统限制值,或队列中的字节总数等于系统限制值),则指定IPC_NOWAIT使得msgsnd立即出错返回EAGAIN。如果没有指定 IPC_NOWAIT,则进程阻塞直到:

有空间可以容纳要发送的消息,或从系统中删除了此队列,或捕捉到一个信号,并从信号处理程序返回

        3.msgctl

msgctl函数对队列执行多种操作。它以及另外两个与信号量和共享存储有关的函数 (semctl和shmctl)是系统VIPC的类似于ioctl的函数。

intmsgctl(int msqid, int cmd, struct msqid_ds *buf);返回:若成功则为 0,出错则为 -1。

cmd参数指定对于由msqid规定的队列要执行的命令:

IPC_STAT取此队列的msqid_ds结构,并将其存放在buf指向的结构中。

IPC_SET按由b u f指向的结构中的值,设置与此队列相关的结构中的下列四个字段:msg_perm.uid、msg_perm.gid、msg_perm;mode和msg_qbytes。此命令只能由下列两种进程执行:一种是其有效用户 ID等于msg_perm.cuid或msg_perm.uid;另一种是具有超级用户特权的进程。只有超级用户才能增加msg_qbytes的值

IPC_RMID从系统中删除该消息队列以及仍在该队列上的所有数据。这种删除立即生效。仍在使用这一消息队列的其他进程在它们下一次试图对此队列进行操作时,将出错返回EIDRM。此命令只能由下列两种进程执行:一种是其有效用户ID 等于msg_perm.cuid或msg_perm.uid;另一种是具有超级用户特权的进程。这三条命令(IPC_STAT、IPC_SET和IPC_RMID)也可用于信号量和共享存储。

       三、信号量

        1.semget

semget函数用以获得一个信号量ID。
int semget(key_t key, int nsems, int flag) ;

返回:若成功则返回信号量 I D,若出错则为- 1
创建一个新集合时,对 semid_ds结构的下列成员赋初值:

对 ipc_perm结构赋初值。该结构中的 mode被设置为flag中的相应许可权位。

sem_otime设置为0。

sem_ctime设置为当前时间。

sem_nsems设置为nsems。

nsems是该集合中的信号量数。如果是创建新集合(一般在服务器中),则必须指定nsems。如果引用一个现存的集合(一个客户机),则将nsems指定为0。

       2.semctl

该函数包含了多种信号量操作。

intsemctl(int semid, int semnum, int cmd, union semun arg);
最后一个参数是个联合( union),而非指向一个联合的指针。

       3.semop

该函数自动执行信号量集合上的操作数组。

intsemop(int semid, struct sembuf semoparray[ ] , size_t nops);返回:若成功则为 0,若出错则为 -1
semoparray是一个指针,它指向一个信号量操作数组。

#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#include <stdio.h>#include <stdlib.h>union semun {int val;struct semid_ds *buf;unsigned short *array;struct seminfo *__buf;};int init_sem(int sem_id,int init_value);int del_sem(int sem_id);int sem_p(int sem_id);int sem_v(int sem_id);int init_sem(int sem_id,int init_value){union semun sem_union;sem_union.val=init_value;if(semctl(sem_id,0,SETVAL,sem_union)==-1){perror("Initial semaphore");return -1;}return 0;}int del_sem(int sem_id){union semun sem_union;if(semctl(sem_id,0,IPC_RMID,sem_union)==-1){perror("Delete semaphore");return -1;}return 0;}int sem_p(int sem_id){struct sembuf sem_b;sem_b.sem_num=0;sem_b.sem_op=-1;sem_b.sem_flg=SEM_UNDO;if(semop(sem_id,&sem_b,1)==-1){perror("P operation");return -1;}return 0;}int sem_v(int sem_id){struct sembuf sem_b;sem_b.sem_num=0;sem_b.sem_op=1;sem_b.sem_flg=SEM_UNDO;if(semop(sem_id,&sem_b,1)==-1){perror("V operation");return -1;}return 0;}

 

0 0