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 2 3 4 5 6 7 8
多个线程: 买菜----择菜 -----洗菜-----切菜----炒菜---端菜----收盘---洗盘
- 工作原理:
二值信号灯:
值为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;
}