Linux-System V IPC(标准进程间通信)

1、消息队列

        消息队列是一种先进先出的队列型数据结构,实际上是系统内核中的一个内部链表。消息被顺序插入队列中,其中发送进程将消息添加到队列末尾,接受进程从队列头读取消息。多个进程可同时向一个消息队列发送消息,也可以同时从一个消息队列中接收消息。发送进程把消息发送到队列尾部,接受进程从消息队列头部读取消息,消息一旦被读出就从队列中删除。

函数原型:

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

        函数功能:向消息队列中发送消息
        函数参数:
                    msqid : 消息队列号
                    msgp  : 消息的结构体地址                    

struct msgbuf {
            long mtype;       /* 消息类型long  必须>0 */
            char mtext[1];    /* 消息的正文(数值、字符、字符串、结构体等 */
              };

                    msgsz : 消息正文的大小  (不包含类型)     
                    msgflg : 发送消息的方式,消息队列为满,默认写阻塞
                                0            阻塞发送
                                IPC_NOWAIT  非阻塞发送
        返回值:成功返回 0

函数原型:

 ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

        函数功能:向消息队列中发送消息
        函数参数
            msqid : 消息队列号
            msgp: 接收消息后存放消息的结构体地址
            msgsz : 接收消息正文的大小  (不包含类型)  
            msgtyp: 接收消息的类型
                         0 : 直接读取第一条消息
                        >0: 读取类型为mtype的消息
                        <0:读取第一条小于等于mtype绝对值的消息
                            -100 -> 100 -> 99 -> 98
                    msgflg: 读取消息的方式,消息队列为空,默认读阻塞
                        0            阻塞
                        IPC_NOWAIT  非阻塞
        返回值:成功返回接收的字节数,失败 -1

函数原型:

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

        函数功能:控制消息队列(获取属性、设置属性、删除等)
        函数参数
            msqid : 消息队列号
            cmd   :  命令
                IPC_STAT : 获取属性 将属性放入buf
                IPC_SET  : 设置属性 讲buf中的值存入刀消息队列的属性中
                IPC_RMID : 删除消息队列
                buf : 属性结构体地址,第二参数为IPC_RMID,该参数没有意义NULL即可

举例:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>

struct msgbuf{
	long mtype;
	char mtext[64];
};

int main(){
	int msgid = 0;				//消息队列号
	key_t key = ftok("/home/linux", 'a');
	
	//创建
    if(-1 == (msgid = msgget(key, IPC_CREAT | 0666))){
    	perror("msgget");return -1;
    }

    struct msgbuf msg;

    //从消息队列中读
    while(1){
        memset(msg.mtext, 0x00, sizeof(msg)-sizeof(long));
        printf("请输入要读取消息的类型 > ");
        scanf("%ld", &msg.mtype);
        //读取
        msgrcv(msgid, &msg, sizeof(msg.mtext), msg.mtype, 0);
        printf("recv data : %s\n", msg.mtext);

        if(strncmp("exit", msg.mtext, 4) == 0)
            break;
    }

    //删除
    msgctl(msgid, IPC_RMID, NULL);

    return 0;	
}

2、共享内存

        是所有进程间最高效的通信方式,因为相当于共享内存分配出的物理地址直接映射到两个进程,绑定,以后在进程中对共享内存操作就相当于对分配出的物理地址操作,不需要用户空间和内核空间数据的拷贝过程,因此是最高效的。

  • 为了防止内存碎片,创建共享内存的大小为一页4096字节的整数倍【4K的整数倍】

函数原型

int shmget(key_t key, size_t size, int shmflg);

        参数

                key : 键值

                size: 创建共享内存的大小,4096整数倍

                shmflg: IPC_CREAT: 不存在时创建,存在也创建 ,直接返回ipc对象标识符

                               IPC_EXCL : 不存在,创建 存在返回错误 EEXIST

        功能:成功返回共享内存号,失败 返回-1

映射函数原型:

void *shmat(int shmid, const void *shmaddr, int shmflg);

        功能:映射共享内存段首地址到当前进程(拿到共享内存段的首地址)

        参数

                shmid: shmget的返回值是 共享内存号

                shmaddr: 将共享内存段关联到当前调用进程的地址处,一般为NULL,交由系统分配

                shmflg : 对共享内存段的操作权限

                        SHM_RDONLY: 只读,并且当前进程对ipc对象具有读权限

                                              0 : 读写权限,并且当前进程对ipc对象具有读写权限

取消映射函数原型:

int shmdt(const void *shmaddr);//功能:取消映射

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

//功能:对共享内存段控制 一般作为删除作用

实例:

write.c

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
int main(){
    key_t key;
    int shmid;
    void *addr = NULL;
    char buf[32] = {0}; 
    
    if(-1 == (key = ftok(".", 'a'))){
        perror("ftok");return -1;
    }
    
    //创建共享内存
    if(-1 == (shmid = shmget(key, 4096, IPC_CREAT | 0666))){
        perror("shmget");return -1;
    }
    
    //映射
    if((void *)-1  == (addr = shmat(shmid, NULL, 0))){
        perror("shmat");return -1;
    }

    //对共享内存段操作
    while(1){
        memset(buf, 0x00, sizeof(buf));
        printf("input > ");
        fgets(buf, sizeof(buf), stdin);
        buf[strlen(buf)-1] = '\0';
        
        sprintf(addr, "%s", buf);
    }
    //取消映射    
    shmdt(addr);

    return 0;
}

read.c

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
int main(){
    key_t key;
    int shmid;
    void *addr = NULL;
    char buf[32] = {0}; 
    
    if(-1 == (key = ftok(".", 'a'))){
        perror("ftok");return -1;
    }

    //获取共享内存号
    if(-1 == (shmid = shmget(key, 4096, IPC_CREAT | 0666))){
        perror("shmget");return -1;
    }
    
    //映射
    if((void *)-1  == (addr = shmat(shmid, NULL, 0))){
        perror("shmat");return -1;
    }
    
    //对共享内存段操作--读
    while(1){
        printf("data=%s\n", (char *)addr);        //没有读阻塞,直接返回
    }
    
    shmdt(addr);
    return 0;
}

3、信号量

        信号量本身是一个计数器,代表了有无资源和有多少资源可用

                P:当一个进程想要访问共享资源的时候,会进行P操作,在进行P操作之前先查看信号量的值是否大于0,如果等于0,则会阻塞,如果大于0,会执行访问临界资源的代码区域,并且将信号量的值-1

                V:给一个信号量释放资源,信号量的值+1,如果一个进程因为信号量原本的值为0而阻塞,当进行V操作之后值+1,此时进程会接触阻塞申请资源执行代码区域

int semget(key_t key, int nsems, int semflg);

        功能:创建信号量

        参数

                key:键值

                nsems: 创建的信号量的个数

                semflg: 标志位

        返回值:成功返回信号量集的标识符,失败 -1

int semctl(int semid, int semnum, int cmd, ...);

        功能:控制信号量

        参数

                semid:信号量集的标识符

                semnum: 要控制的信号量的编号(一个信号量集中编号从0开始

                cmd:命令

                        IPC_STAT IPC_SET 对属性操作

                        IPC_INFO 获取信息

                        IPC_RMID 删除信号量集

                        GETALL 返回array中所有信号量的semval(即当前值)。参数semnum被忽略。调用进程必须对信号量集具有读权限。

                        GETVAL 返回编号为Semnum的信号量的当前值(以返回值形式得到)

                        SETALL 设置所有信号量集中的信号量的值,调用进程必须对信号量集具有写权限

                        SETVAL 设置编号为Semnum的信号量的值为第四个参数或者第四个参数联合体中的第一个成员

                        ...: 可变参数 具体取决于第三个参数 也可单独使用

union semun {
               int              val;    /* Value for SETVAL */
               struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
               unsigned short  *array;  /* Array for GETALL, SETALL */
               struct seminfo  *__buf;  /* Buffer for IPC_INFO */

           };

        返回值:失败-1 成功取决于第三个参数 GETVAL the value of semval.

int semop(int semid, struct sembuf *sops, size_t nsops);

        功能:对信号量操作

        参数

                semid: 信号量集编号

                sops: 结构体指针 unsigned short sem_num; 

                short sem_op 信号量的操作 P申请资源 -1 / V释放资源 +1

                IPC_NOWAIT 非阻塞 0阻塞

                SEM_UNDO 进程终止时自动撤销 

                nsops: 操作的信号量的个数

        返回值:成功返回 0     失败 -1

  • 35
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值