进程--------->第三天,systemV IPC对象(消息队列、共享内存、信号量)

systemV IPC对象

ipcs -----查看系统5的IPC对象

1.特点:

每个IPC对象有唯一的ID值,由系统分配的

每个IPC对象有一个关联的key值(ftok函数)

key值为0表示私有对象,若key非0和ID值一一对应

2.获得key

消息队列,共享内存都需要获得key值#include <sys/types.h>

#include <sys/ipc.h>

参数1:path存在且可访问的文件路径

参数2: 不能为0

返回值:成功返回key值,失败返回-1

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

3.消息队列:

1.特点:

1.是一种特殊的链表队列,满足先入先出

2.消息队列是按照类型来发送/接受信息

2.使用的函数

打开和创建消息队列

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

参数1:通过ftok获得key

参数2:

      IPC_CREAT |0600如果key不存在,则创建,若存在,返回id中

      IPC_EXCL  如果key在,返回失败

      IPC_NOWAIT 非阻塞

返回值:成功返回消息队列代号.失败返回-1

int msgget(key_t key, int msgflg);

读写数据

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

参数1:msgget获得的id值

参数2:自定义的结构体,

struct msgBuf{

                long mtype;      //消息队列的类型

                char mtext[100];   //数据

}

参数3:发送消息的字节数

参数4:0         //消息发送成功返回,无空间阻塞

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

参数1:msgget获得的id值

参数2:自定义的结构体,

struct msgBuf{

            long mtype;      //消息队列的类型

            char mtext[100];   //数据

}

参数3:接收消息的字节数

参数4:接收消息的数据类型

参数5: 消息成功返回,无空间阻塞

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

控制消息队列

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

参数1:msgget获得ip的值

参数2:  IPC_RMID 删除

            IPC_SET   设置参数

IPC_STAT  获得参数

参数3:一般为NULL

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

#ifndef MSG_H
#define MSG_H
//类型定义
typedef struct msgBuf
{
	long mtype;//信息类型
	char mtext[100];//信息数据
}Msg;
//引入库头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#endif
//消息队列

#include <stdio.h>
#include "msg.h"

int main(int argc, const char *argv[])
{
	//1.获得key的值
	key_t key=0;
	key=ftok("./",1);
	if(0>key)
	{
		perror("ftok error");
		return -1;
	}

	//2.获得消息队列的代号
	int msgid=0;
	msgid=msgget(key,IPC_CREAT|0600);
	if(0>msgid)
	{
		perror("msgget error");
		return -1;
	}
	//3.发送接收数据
	Msg msgA,msgB;
	msgA.mtype=1;
	msgB.mtype=2;
	while(1)
	{
		printf("A: ");
		scanf("%s",msgA.mtext);
		//将类型发送给对方
		//参数4:0
		msgsnd(msgid,&msgA,sizeof(msgA),0);
		
		//接收数据
		//参数4:接收的数据类型
		//参数5:0
		memset(&msgB,'\0',sizeof(msgB));
		msgrcv(msgid,&msgB,sizeof(msgB),msgB.mtype,0);
		printf("B:%s\n",msgB.mtext);
	}

	//4.删除队列
	//参数2:IPC_RMID表示删除
	//参赛3:NULL
	msgctl(msgid,IPC_RMID,NULL);
	return 0;
}

//消息队列

#include <stdio.h>
#include "msg.h"

int main(int argc, const char *argv[])
{
	//获得key的值
	key_t key=0;
	key=ftok("./",1);
	if(0>key)
	{
		perror("ftok error");
		return -1;
	}

	//获得消息队列的代号
	int msgid=0;
	msgid=msgget(key,IPC_CREAT);
	if(0>msgid)
	{
		perror("msgget error");
		return -1;
	}

	//接收发送数据
	Msg msgA,msgB;
	msgA.mtype=1;
	msgB.mtype=2;
	while(1)
	{
		//接收数据
		//参数4:0
		//参数5:接收数据的类型
		memset(&msgA,'\0',sizeof(msgA));
		msgrcv(msgid,&msgA,sizeof(msgA),msgA.mtype,0);
		printf("A:%s\n",msgA.mtext);

		//发送数据
		//参数4:0
		printf("B: ");
		scanf("%s",msgB.mtext);
		msgsnd(msgid,&msgB,sizeof(msgB),0);
	}

	//删除队列
	//参数2:IPC_RMID表示删除
	//参数3:NULL
	msgctl(msgid,IPC_RMID,NULL);
	return 0;
}

4.共享内存

1.特点:

共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,

共享内存是在内核空间创建,需要将内核共享内存区映射到用户进程中

由于多个进程可同时访问共享内存,因此需要同步(信号量)和互斥机制来配合

2.使用的函数

shmget函数:

#include <sys/ipc.h>

#include <sys/shm.h>

/*

函数名:shmget

函数功能:获得共享内存

函数参数:key:共享内存的键值,多个进程可以通过它访问同一个共享内存。ftok()获得

其中有个特殊值 IPC_PRIVATE,用于创建当前进程的私有共享内存。

size:共享内存的大小

shmflg:同open()函数的权限位,也可以使用八进制表示法

                IPC_CREAT|0666

不管是否已存在该块共享内存,则都会返回共享内存的ID,若不存在则新建

IPC_EXCL

不管有没有该块共享内存,返回-1

函数返回值:

成功:共享内存段标识符

失败:-1

*/

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

shmat函数:

#include <sys/types.h>

#include <sys/shm.h>

函数参数:

shmid:要映射的共享内存区标识符。

shmaddr:将共享内存映射到指定地址若为NULL,则表示系统自动分配地址,并把该段共享,内存映射到调用进程的地址空间)

shmflg:SHM_RDONLY:共享内存只读

默认0:共享内存可读可写

函数返回值:成功:被映射的段地址

     出错:-1

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

shmdt函数:

#include <sys/types.h>

#include <sys/shm.h>

函数原型:int shmdt(const void *shmaddr);

函数参数:shmaddr:被映射的共享内存段地址

函数返回值:

成功:0

失败:-1

#include <sys/ipc.h>

#include <sys/shm.h>

函数原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);

函数参数: 参数1:shmid:要映射的共享内存区标识符。

   参数2:

IPC_RMID 表示删除

IPC_SET   设置参数

IPC_STAT  获得参数

   参数3:NULL

函数返回值:

成功:0

失败:-1

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

//共享内存,写操作

#include <stdio.h>
#include "shm.h"

int main(int argc, const char *argv[])
{
	//1.获得key的值,ftok
	key_t key=0;
	key=ftok("./",66);
	if(0>key)
	{
		perror("ftok error");
		return -1;
	}

	//2.创建共享内存,shmget
	int shmid=0;
	shmid=shmget(key,1024,IPC_CREAT|0666);

	//3.映射共享内存到具体的进程空间,shmat
	char *pShm=NULL;
	pShm=shmat(shmid,NULL,0);

	//4.写
	memset(pShm,'\0',sizeof(pShm));
	strcpy(pShm,"hello");

	//5.分离映射的共享内存,shmdt
	shmdt(pShm);

	//6.删除共享内存,shmctl	
	shmctl(shmid,IPC_RMID,NULL);
	return 0;
}

//共享内存,读操作

#include <stdio.h>
#include "shm.h"

int main(int argc, const char *argv[])
{
	//1.获得key的值,ftok
	key_t key=0;
	key=ftok("./",66);
	if(0>key)
	{
		perror("ftok error");
		return -1;
	}

	//2.创建共享内存,shmget
	int shmid=0;
	shmid=shmget(key,1024,IPC_CREAT|0666);

	//3.映射共享内存到具体的进程空间,shmat
	char *pShm=NULL;
	pShm=shmat(shmid,NULL,0);

	//4.读
	sleep(5);
	printf("%s\n",pShm);

	//5.分离映射的共享内存,shmdt
	shmdt(pShm);

	//6.删除共享内存,shmctl	
	shmctl(shmid,IPC_RMID,NULL);
	return 0;
}

5.信号量

共享内存------公共区域

  1. 实现进程间的同步

和共享内存配合使用,帮助共享内存实现同步

1       2         3        4       5      6      7      8

多个线程:   买菜----择菜 -----洗菜-----切菜----炒菜---端菜----收盘---洗盘

  1. 工作原理:

二值信号灯:

值为0或1。与互斥锁类似,资源可用时值为1,不可用时值为0。

计数信号灯:

值在0到n之间。用来统计资源,其值代表可用资源数

等待操作是等待信号灯的值变为大于0,然后将其减1;而释放操作则相反,用来唤醒等待资源的进程或者线程

2.使用的函数

sem_open:

#include <fcntl.h>

#include <sys/stat.h>

#include <semaphore.h>

sem_t *sem_open(const char *pathname, int oflag);

/*

 *函数名:sem_open

 *函数功能:打开一个信号量,如果信号量不存在,则创建信号量

 *函数参数:

 * const char *pathname:信号量的名字(标识)

 * int oflag:同文件IO的创建时的权限

 * O_CREAT | O_RDWR

 * mode_t mode:同文件权限

 * unsigned in value:信号量的初始值

 *函数返回值:sem_t *:成功返回信号量操作对象的指针

 */

sem_t *sem_open(const char *pathname, int oflag, mode_t mode, unsigned int value);

sem_getvalue:

#include <semaphore.h>

/*

 *函数名:sem_getvalue

 *函数功能:获取当前信号量的值

 *函数参数:

 * sem_t *sem:信号量的操作指针

 * int *sval:存储信号量值的内存首地址

 *函数返回值:int:成功返回0,失败返回-1

 */

int sem_getvalue(sem_t *sem, int *sval);

sem_wait:

#include <semaphore.h>

/*

 *函数名:sem_wait

 *函数功能:信号量值减一

 *函数参数:sem_t *sem:信号量的操作指针

 *函数返回值:int:成功返回0,失败返回-1

 */

int sem_wait(sem_t *sem);

sem_post:

#include <semaphore.h>

/*

 *函数名:sem_post

 *函数功能:信号量值加一

 *函数参数:sem_t *sem:信号量的操作指针

 *函数返回值:int:成功返回0,失败返回-1

 */

int sem_post(sem_t *sem);

sem_close:

#include <semaphore.h>

/*

 *函数名:sem_close

 *函数功能:关闭一个有名信号量

 *函数参数:sem_t *sem:信号量的操作指针

 *函数返回值:int:成功返回0,失败返回-1

 */

int sem_close(sem_t *sem);

注意:进程中使用的信号量,称之为有名信号量

 编译时链接库 -lpthread

#ifndef _SHM_H
#define _SHM_H

//引入库头文件
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#endif
//信号量和共享内存配合使用,实现进程间的同步

#include <stdio.h>
#include "shm.h"

int main(int argc, const char *argv[])
{
	//1.获得key的值,ftok
	key_t key=0;
	key=ftok("./",66);
	if(0>key)
	{
		perror("ftok error");
		return -1;
	}

	//2.创建共享内存,shmget
	int shmid=0;
	shmid=shmget(key,1024,IPC_CREAT|0666);

	//3.映射共享内存到具体的进程空间,shmat
	char *pShm=NULL;
	pShm=shmat(shmid,NULL,0);
	
	//1.1打开信号量,设置初始值
	sem_t *mySem=NULL;
	mySem=sem_open("mySem",O_CREAT|O_RDWR,0664,4);
	if(NULL==mySem)
	{
		perror("open error");
		return -1;
	}
	
	

	while(1)
	{
		sleep(5);
		//1.2获得当前信号量的值
		int sem_v;
		sem_getvalue(mySem,&sem_v);
		if(4==sem_v)
		{
			//1.3信号量值减一(等待操作)
			sem_wait(mySem);
			memset(pShm,'\0',sizeof(pShm));
			strcpy(pShm,"买菜");
			printf("%s\n",pShm);
			/*1.4信号量值加一(释放操作)
			sem_post(mySem);
			sem_post(mySem);
			sem_post(mySem);
			sem_post(mySem);*/	
		}
	}

	//5.分离映射的共享内存,shmdt
	shmdt(pShm);

	//6.删除共享内存,shmctl	
	shmctl(shmid,IPC_RMID,NULL);
	return 0;
}
//信号量和共享内存配合使用,实现进程间的同步

#include <stdio.h>
#include "shm.h"

int main(int argc, const char *argv[])
{
	//1.获得key的值,ftok
	key_t key=0;
	key=ftok("./",66);
	if(0>key)
	{
		perror("ftok error");
		return -1;
	}

	//2.创建共享内存,shmget
	int shmid=0;
	shmid=shmget(key,1024,IPC_CREAT|0666);

	//3.映射共享内存到具体的进程空间,shmat
	char *pShm=NULL;
	pShm=shmat(shmid,NULL,0);
	
	//1.1打开信号量,设置初始值
	sem_t *mySem=NULL;
	mySem=sem_open("mySem",O_CREAT|O_RDWR,0664,4);
	if(NULL==mySem)
	{
		perror("open error");
		return -1;
	}
	
	

	while(1)
	{
		sleep(5);
		//1.2获得当前信号量的值
		int sem_v;
		sem_getvalue(mySem,&sem_v);
		if(3==sem_v)
		{
			//1.3信号量值减一(等待操作)
			sem_wait(mySem);
			memset(pShm,'\0',sizeof(pShm));
			strcpy(pShm,"摘菜");
			printf("%s\n",pShm);
			/*1.4信号量值加一(释放操作)
			sem_post(mySem);
			sem_post(mySem);
			sem_post(mySem);
			sem_post(mySem);*/	
		}
	}

	//5.分离映射的共享内存,shmdt
	shmdt(pShm);

	//6.删除共享内存,shmctl	
	shmctl(shmid,IPC_RMID,NULL);
	return 0;
}
//信号量和共享内存配合使用,实现进程间的同步

#include <stdio.h>
#include "shm.h"

int main(int argc, const char *argv[])
{
	//1.获得key的值,ftok
	key_t key=0;
	key=ftok("./",66);
	if(0>key)
	{
		perror("ftok error");
		return -1;
	}

	//2.创建共享内存,shmget
	int shmid=0;
	shmid=shmget(key,1024,IPC_CREAT|0666);

	//3.映射共享内存到具体的进程空间,shmat
	char *pShm=NULL;
	pShm=shmat(shmid,NULL,0);
	
	//1.1打开信号量,设置初始值
	sem_t *mySem=NULL;
	mySem=sem_open("mySem",O_CREAT|O_RDWR,0664,4);
	if(NULL==mySem)
	{
		perror("open error");
		return -1;
	}
	
	

	while(1)
	{
		sleep(5);
		//1.2获得当前信号量的值
		int sem_v;
		sem_getvalue(mySem,&sem_v);
		if(2==sem_v)
		{
			//1.3信号量值减一(等待操作)
			sem_wait(mySem);
			memset(pShm,'\0',sizeof(pShm));
			strcpy(pShm,"洗菜");
			printf("%s\n",pShm);
			/*1.4信号量值加一(释放操作)
			sem_post(mySem);
			sem_post(mySem);
			sem_post(mySem);
			sem_post(mySem);*/	
		}
	}

	//5.分离映射的共享内存,shmdt
	shmdt(pShm);

	//6.删除共享内存,shmctl	
	shmctl(shmid,IPC_RMID,NULL);
	return 0;
}
//信号量和共享内存配合使用,实现进程间的同步

#include <stdio.h>
#include "shm.h"

int main(int argc, const char *argv[])
{
	//1.获得key的值,ftok
	key_t key=0;
	key=ftok("./",66);
	if(0>key)
	{
		perror("ftok error");
		return -1;
	}

	//2.创建共享内存,shmget
	int shmid=0;
	shmid=shmget(key,1024,IPC_CREAT|0666);

	//3.映射共享内存到具体的进程空间,shmat
	char *pShm=NULL;
	pShm=shmat(shmid,NULL,0);
	
	//1.1打开信号量,设置初始值
	sem_t *mySem=NULL;
	mySem=sem_open("mySem",O_CREAT|O_RDWR,0664,4);
	if(NULL==mySem)
	{
		perror("open error");
		return -1;
	}
	
	

	while(1)
	{
		sleep(5);
		//1.2获得当前信号量的值
		int sem_v;
		sem_getvalue(mySem,&sem_v);
		if(1==sem_v)
		{
			//1.3信号量值减一(等待操作)
			sem_wait(mySem);
			memset(pShm,'\0',sizeof(pShm));
			strcpy(pShm,"切菜");
			printf("%s\n",pShm);
			//1.4信号量值加一(释放操作)
			sem_post(mySem);
			sem_post(mySem);
			sem_post(mySem);
			sem_post(mySem);	
		}
	}

	//5.分离映射的共享内存,shmdt
	shmdt(pShm);

	//6.删除共享内存,shmctl	
	shmctl(shmid,IPC_RMID,NULL);
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值