Linux ipc------System V概述

      System V IPC指的是AT&T在System V.2发行版中引入的三种进程间通信工具:

(1)信号量,用来管理对共享资源的访问;

(2)共享内存,用来高效地实现进程间的数据共享;

(3)消息队列,用来实现进程间数据的传递。

      我们把这三种工具统称为System VIPC对象,每个对象都具有一个唯一的IPC标识符(identifier)。


IPC命令

Linux中,与IPC相关的命令包括:ipcs、ipcrm(释放IPC)。

1、使用IPCS可以查看共享内存、信号量、消息队列的状态。

ipcs -a 是默认的输出信息 打印出当前系统中所有的进程间通信方式的信息

ipcs -m 打印出使用共享内存进行进程间通信的信息

ipcs -q 打印出使用消息队列进行进程间通信的信息

ipcs -s 打印出使用信号进行进程间通信的信息

ipcs -c 输出ipc各种方式的在该系统下的限制条件信息

2、ipcrm除一个消息对象。或者共享内存段,或者一个信号集,同时会将与ipc对象相关链的数据也一起移除。

ipcrm -M shmkey 移除用shmkey创建的共享内存段

ipcrm -m shmid 移除用shmid标识的共享内存段

ipcrm -Q msgkey 移除用msqkey创建的消息队列

ipcrm -q msqid 移除用msqid标识的消息队列

ipcrm -S semkey 移除用semkey创建的信号

ipcrm -s semid 移除用semid标识的信号


IPC key

       如何让多个进程都访问某一个特定的IPC对象,需要一个IPC关键字(IPC key),每一个IPC对象都与一个IPC关键字(IPC key)相关联。这样就解决了多进程在一个IPC对象上汇合的问题。创建一个IPC对象时需要指定一个键值,类型为key_t。内核负责把IPC关键字转换成IPC标识符。在linux内核中定义了一个结构体

struct ipc_perm
{
key_t key; 关键字
uid_t uid; /*共享内存所有者的有效用户ID */
gid_t gid; /* 共享内存所有者所属组的有效组ID*/ 
uid_t cuid; /* 共享内存创建 者的有效用户ID*/
gid_t cgid; /* 共享内存创建者所属组的有效组ID*/
unsigned short mode; /* Permissions + SHM_DEST和SHM_LOCKED标志*/
unsignedshort seq; /* 序列号*/
};

    key_t key就是IPC key,是识别这个共享通道的钥匙。也叫做键。

1.、IPC键(IPC key)
    key_t这个数据类型在<sys/types.h>有定义,通常是一个至少32位的整数。我们通常使用ftok()函数(可以如此记忆:file to key)把一个已存在的路径名和一个整数标识符转换成一个key_t值,称为IPC键。 选择IPC关键字,可以使用如下三种方式:
a)IPC_PRIVATE。由内核负责选择一个关键字然后生成一个IPC对象并把IPC标识符直接传递给另一个进程。
b)直接选择一个关键字。
c)使用ftok()函数生成一个关键字。

2、ftok原型如下:
key_t ftok( char * fname, int id )

头文件:

#include <sys/types.h>  
#include <sys/ipc.h>  
参数:
fname就时你指定的文件名(该文件必须是存在而且可以访问的),id是子序号,虽然为int,但是只有8个比特被使用(0-255)。
返回值:
当成功执行的时候,一个key_t值将会被返回,否则 -1 被返回。

System V IPC对象总结

1、信号量(Semaphores)
    System V的信号量集表示的是一个或多个信号量的集合。内核为每个信号量集维护一个semid_ds数据结构,而信号量集中的每个信号量使用一个无名结构体表示,这个结构体至少包含以下成员:
struct{
unsigned short semval;//信号量值,总是>=0
pid_t sempid; //上一次操作的pid

};
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>


(1)创建或访问信号量
* int semget(key_t key,int nsems,int flag);
nsems指定信号量集中信号量的个数,如果只是获取信号量集的标识符(而非新建),那么nsems可以为0。flag的低9位作为信号量的访问权限位,类似于文件的访问权限;如果flag中同时指定了IPC_CREAT和IPC_EXCL,那么如果key已与现存IPC对象想关联的话,函数将会返回EEXIST错误。例如,flag可以为IPC_CREAT|0666。

(2)控制信号量集
* int semctl(int semid,int semnum,int cmd,union semun arg);
对semid信号量集合执行cmd操作;cmd常用的两个值是:SETVAL初始化第semnum个信号量的值为arg.val;IPC_RMID删除信号量。

(3)对一个或多个信号量进行操作
* int semop(int semid,struct sembuf *sops,unsigned nsops);
* struct sembuf{
unsigned short sem_num; //信号量索引
short sem_op; //对信号量进行的操作,常用的两个值为-1和+1,分别代表P、V操作
short sem_flag; //比较重要的值是SEM_UNDO:当进程结束时,相应的操作将被取消;同时,如果进程结束时没有释放资源的话,系统会自动释放
};

2、共享内存
共享内存允许两个或多个进程共享一定的存储区,因为不需要拷贝数据,所以这是最快的一种IPC。
#include <sys/ipc.h>
#include <sys/shm.h>


(1)创建或访问共享内存
* int shmget(key_t key,size_t size,int shmflg);

(2)附加共享内存到进程的地址空间
* void *shmat(int shmid,const void *shmaddr,int shmflg);//shmaddr通常为NULL,由系统选择共享内存附加的地址;shmflg可以为SHM_RDONLY

(3)从进程的地址空间分离共享内存
* int shmdt(const void *shmaddr); //shmaddr是shmat()函数的返回值

(4)控制共享内存
* int shmctl(int shmid,int cmd,struct shmid_ds *buf);
* struct shmid_ds{
struct ipc_perm shm_perm;

};
cmd的常用取值有:(a)IPC_STAT获取当前共享内存的shmid_ds结构并保存在buf中(2)IPC_SET使用buf中的值设置当前共享内存的shmid_ds结构(3)IPC_RMID删除当前共享内存

3、消息队列
消息队列保存在内核中,是一个由消息组成的链表。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>


(1)创建或访问消息队列
* int msgget(key_t key,int msgflg);

(2)操作消息队列
* int msgsnd(int msqid,const void *msg,size_t nbytes,int msgflg);
msg指向的结构体必须以一个long int成员开头,作为msgrcv()的消息类型,必须大于0。nbytes指的是msg指向结构体的大小,但不包括long int部分的大小
* ssize_t msgrcv(int msqid,void *msg,size_t nbytes,long msgtype,int msgflg);
如果msgtype是0,就返回消息队列中的第一个消息;如果是正整数,就返回队列中的第一个该类型的消息;如果是负数,就返回队列中具有最小值的第一个消息,并且该最小值要小于等于msgtype的绝对值。

(3)控制消息队列
* int msgctl(int msqid,int cmd,struct msqid_ds *buf);
* struct msqid_ds{
struct ipc_perm msg_perm;

};


4、总结

(1)使用semget()/shmget()/msgget()函数根据IPC关键字key和一个标志flag创建或访问IPC对象。如果key是IPC_PRIVATE;或者key尚未与已经    存在的IPC对象相关联且flag中包含IPC_CREAT标志,那么就会创建一个全新的IPC对象。

(2)使用semctl()/shmctl()/msgctl()函数修改IPC对象的属性。

(3)使用semctl()/shmctl()/msgctl()函数和IPC_RMID标志销毁IPC实例。





你可能感兴趣的:(linux,进程同步,消息队列,信号量,共享内存)