进程间通信之system V IPC对象(共享内存、消息队列、信号灯集)

目录

一、system V IPC对象

1、key值地获取

2、共享内存

使用共享内存流程:

2、消息队列

消息队列的使用流程:

练习:使用两个进程,两个进程间互相收发数据

3、信号灯集


 

一、system V IPC对象

IPC对象包括:共享内存、消息队列、信号灯集

每个IPC对象由唯一ID

IPC创建后一直存在,直到显式删除(程序中注意及时关闭)

每个IPC对象有个关联的key

ipcs:查看IPC对象

所有的IPC对象只能通过用户显式地进行删除

1、key值地获取

       #include <sys/types.h>
       #include <sys/ipc.h>

       key_t ftok(const char *pathname, int proj_id);


参数:
    pathname:任意路径
    proj_id:任意字符
返回值:
    成功返回key值,失败返回-1

2、共享内存

共享内存是进程间通信效率最高的一种通信机制

使用共享内存流程:

1、创建或者打开共享内存 -- shmget()

       #include <sys/ipc.h>
       #include <sys/shm.h>

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


参数:
    key:通过ftok得到或者使用IPC_PRIVATE(创建私有共享内存)
    size:共享内存的大小
    shmflg:创建共享内存权限,一般填0664 | IPC_CREAT
    
返回值:
    成功返回共享内存ID,失败返回-1

 2、映射共享内存shmat()

       #include <sys/types.h>
       #include <sys/shm.h>

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

参数:
    shmid:共享内存ID
    shmaddr:NULL表示系统自动分配
    shmflg:SHM_RDONLY -- 只读
    		0 -- 读写
返回值:
    成功返回映射地址,失败返回(void*)-1

3、访问共享内存

4、取消映射 -- shmdt()

       #include <sys/types.h>
       #include <sys/shm.h>

       int shmdt(const void *shmaddr);
参数:
    shmaddr:要取消的映射的地址
返回值:
    成功返回0,失败返回-1

5、删除共享内存 -- shmctl()

       #include <sys/ipc.h>
       #include <sys/shm.h>

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

参数:
    shmid:共享内存ID
    cmd:操作共享内存的命令
    		IPC_STAT:获取共享内存信息,存于第三个参数结构体指针
    		IPC_SET:设置共享内存信息
    		IPC_RMID:删除共享内存,第三个参数填空
返回值:
    成功返回0,失败返回-1

2、消息队列

消息队列的使用流程:

1、创建、打开消息队列 -- msgget

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

       int msgget(key_t key, int msgflg);

参数:
    key:通过ftok得到的key值或者使用IPC_CREAT
    shmflg:创建消息队列的权限,一般填 0664 |IPC_CREAT
返回值:
    成功返回消息队列ID,失败返回-1
    

2、发送消息 -- msgsnd

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

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

     
参数:
    msqid:消息队列id
    msgp:跟发送消息相关结构体的首地址
    msgsz:消息结构体中正文内容的大小
    msgflg: 0 -- 以阻塞方式发送消息
        	IPC_NOWAIT -- 以阻塞方式发送消息
返回值:
    成功返回0,失败返回-1
    
用法:
    #define LEN (sizeof(MSG)-sizeof(long))
    typedef struct msgbuf
    {
        long mtype;
        char mtext[64];
    }MSG;

	MSG msg;
	char buf[64] = {0};
	msg.mtype = 100;
	fgets(buf , 64, stdin);
	strcpy(msg.mtext, buf);

	msgsnd(msgid, &msg, LEN, 0)

3、接受消息 -- msgrcv

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

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

参数:
    msqid:接收消息队列id
    msgp:跟接收消息相关结构体的首地址
    msgsz:接收消息结构体中正文内容的大小
    msgflg: 0 -- 以阻塞方式发送消息
        	IPC_NOWAIT -- 以阻塞方式发送消息
返回值:
    成功返回0,失败返回-1

4、删除消息队列 -- msgctl

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

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

例:
    msgctl(msgid)
    

练习:使用两个进程,两个进程间互相收发数据

A:

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

#define LEN (sizeof(MSG)-sizeof(long))
#define typeA 100
#define typeB 200

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


int main(int argc, char *argv[])
{ 
    MSG msg;
    int ret = 0;
    char buf[64] = {0};
    key_t key = ftok(".", 'i');   //获取key值
    if(key < 0)
    {
        perror("ftok");
        exit(-1);
    }

    int msgid = msgget(key, 0664 | IPC_CREAT);   //创建、打开消息队列得到msgid
    if(msgid < 0)
    {
        perror("msgget");
        exit(-1);
    }

    while(1)
    {
    	memset(&msg, 0, sizeof(MSG));   //清空结构体
    	msg.mtype = typeA;
    	printf("input>>");
    	fgets(buf, 64, stdin);  	    	
    	strcpy(msg.mtext, buf);
        ret = msgsnd(msgid, &msg, LEN, 0);
        if(ret < 0)
        {
            perror("msgsnd");
            exit(-1);
        }
	    if(strcmp(buf, "quit\n") == 0)
    	{
    		printf("bye~ \n");
    		break;
    	}
    	
    	
		memset(&msg, 0, sizeof(MSG));   //清空结构体
        ret = msgrcv(msgid, &msg, LEN, typeB, 0);
        if(ret < 0)
        {
            perror("msgrcv");
            exit(-1);
        }
        if(strcmp(msg.mtext, "quit\n") == 0)
        {
        	printf("bye~\n");
        	msgctl(msgid, IPC_RMID, NULL);
        	break;
        } 
        printf("recv:%s",msg.mtext);

    }
	
	
    return 0;
} 

B:

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

#define LEN (sizeof(MSG)-sizeof(long))
#define typeA 100
#define typeB 200

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


int main(int argc, char *argv[])
{ 
    MSG msg;
    int ret = 0;
    char buf[64] = {0};
    key_t key = ftok(".", 'i');   //获取key值
    if(key < 0)
    {
        perror("ftok");
        exit(-1);
    }

    int msgid = msgget(key, 0664 | IPC_CREAT);   //创建、打开消息队列得到msgid
    if(msgid < 0)
    {
        perror("msgget");
        exit(-1);
    }

    while(1)
    {
    	memset(&msg, 0, sizeof(MSG));   //清空结构体
        ret = msgrcv(msgid, &msg, LEN, typeA, 0);
        if(ret < 0)
        {
            perror("msgrcv");
            exit(-1);
        }
        if(strcmp(msg.mtext, "quit\n") == 0)
        {
        	printf("bye~\n");
        	msgctl(msgid, IPC_RMID, NULL);
        	break;
        }      
        printf("recv:%s",msg.mtext);
    
    	memset(&msg, 0, sizeof(MSG));   //清空结构体
    	msg.mtype = typeB;
    	printf("input>>");
    	fgets(buf, 64, stdin);
    	strcpy(msg.mtext, buf);
        ret = msgsnd(msgid, &msg, LEN, 0);
        if(ret < 0)
        {
            perror("msgsnd");
            exit(-1);
        }
       	if(strcmp(buf, "quit\n") == 0)
    	{
    		printf("bye~ \n");
    		break;
    	}
    }
	
	
    return 0;
} 

3、信号灯集

(1)semget()

        创建信号灯集

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

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

参数:
    key:产生信号灯id需要使用的键值,可以用IPC_PRIVATE 或 ftok来获取
    semflg:标志位,设置信号灯权限
    		IPC_CREAT:创建新的信号灯
    
返回值:
    成功返回信号灯id号,错误返回-1

 

(2)semctl()

        设置信号灯初值(或其他操作:比如 删除信号灯)

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

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

参数:
    semiid:信号灯标识id
    semnum:
    cmd:控制命令
    	IPC_RMID:删除信号灯
        IPC_SET: 设置信号灯相关属性
	    ...: 可变参数  如果第三个参数是 IPC_RMID 则第四个参数可以不传
				      如果第三个参数是 IPC_SET 则需要传递第四个参数.
				 参数类型是一个共用体:
    
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
                                           (Linux-specific) */
           };

返回值:
    成功根据cmd值的不同而返回不同的值,失败反返回-1

 

(3)semop()

        实现P、V操作

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

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

参数:
    semid:信号灯标识id
    sops:信号灯操作结构体数组首地址
    	  struct sembuf
          {
           		unsigned short sem_num;  /* semaphore number */
           		short          sem_op;   /* semaphore operation */
           		short          sem_flg;  /* operation flags */

          }
			sem_num:信号灯编号
            sem_op:
                1:表示V操作(释放资源)
                -1:表示P操作(申请资源)
            sem_flg:通常为0表示阻塞等待
    nsops:表示需要控制多少个信号灯
返回值:
    成功返回0,失败返回-1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值