Linux c 基于内存的进程通信—共享内存、共享队列(消息队列)

Linux c 基于内存的进程通信—共享内存、共享队列(消息队列)

基于内存的进程通信:

1. 内核共享内存

编程模型:

1.1.创建共享内存,得到一个ID shmget

1.2.把ID影射成虚拟地址(挂载) shmat

1.3.使用虚拟地址访问内核共享内存使用任何内存函数与运算符号 1.4.卸载虚拟地址 shmdt

1.5.删除共享内存 shctl(修改/获取共享内存的属性)

案例:

A.创建共享内存,并且修改内存数据

1. 创建共享内存

#include

intshmget(key_t key,//为什么需要key

int size,//共享内存大小

int flags//共享内存的属性与权限

)

为什么要key_t:

约定创建与访问的是同一个共享内存。Key为两个进程之间访问同一块共享内存的约定

注:key需要唯一性,因为我们不能保证我们自己定义的key的唯一性,所以为了保证kay的唯一性,我们需要用某个文件对应的整数来充当kay值,可以用ftok函数来将一个文件转化为一个kay值。(一般我们用两个进程的共同的工程目录文件来确定kay值)

ftok函数:

#include

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

参数二:一个控制因子。建议在0—255之间

第三个参数:

方式|权限

方式:创建 IPC_CREAT IPC_EXCL(如果内存已经创建,直接错误返回)

打开:0

常见的两种方式:

创建:IPC_CREAT|IPC_EXCL | 0666;

打开:0

返回:

成功返回共享内存ID

失败返回-1

失败返回-1

B.根据ID得到共享内存,并且访问内存数据。

挂载共享内存

void* shmat(int id,

void*startaddr,//0:系统指定首地址

intflags)//挂载方式,建议0默认读写,可以使用IPC_RDONLY

返回值:合法地址成功,-1失败

C.删除

intshmctl(int id,//被操作的共享内存ID

inthow,//操作方式:一共三种操作

structshmid_ds*ds)//共享内存属性

how:

IPC_STAT

IPC_SET //修改属性

IPC_RMID //删除 参数三无用

案例代码:

ShmA.c

#include

#include

#include

#include

#include

void main()

{

key_t key;

int shmid;

int * p;

//1.创建共享内存

key=ftok( “.” , 255 ); //用当前路径的目录来确定kay值

if(key == -1) printf(“ftok error%m\n”) , exit( - 1 );

shmid=shmget( key , 4 , IPC_CREAT|IPC_EXCL | 0666 );

if(shmid == -1) printf(“shmget error %m\n”) , exit( -1 );

//2.挂载共享内存

p=shmat( shmid , 0 , 0);

if(p==(int *) - 1) printf(“at error %m\n”) , exit( -1 );

//3.访问共享内存

*p=999;

//4.卸载共享内存

shmdt(shmid);

//删除共享内存

shctl( shmid , IPC_RMID , 0);

}

不创建共享内存,只访问已有的

shmB.c

ShmA.c

#include

#include

#include

#include

#include

void main()

{

key_t key;

int shmid;

int * p;

//1.得到共享内存

key=ftok( “.” , 255 ); //用当前路径的目录来确定kay值

if(key == -1) printf(“ftok error%m\n”) , exit( - 1 );

shmid=shmget( key , 4 ,0 );

if(shmid == -1) printf(“shmget error %m\n”) , exit( -1 );

//2.挂载共享内存

p=shmat( shmid , 0 , 0);

if(p==(int *) - 1) printf(“at error %m\n”) , exit( -1 );

//3.访问共享内存

printf(“%d\n”,*p);

//4.卸载共享内存

shmdt(shmid);

}

2. 内核共享队列(有序)

编程模型:

2.1.创建共享队列/得到队列msgget

2.2.使用队列(发送消息msgsnd/接收消息msgrcv)

2.3.删除队列msgctl

案例:

创建共享队列

#include

intmsgget(key_t,int); 除了不用指定大小,和shmget函数的参数一样

发送消息

intmsgsnd(

intid,//消息队列ID

constvoid *msg,//要发送消息

size_tlen,//消息的长度

int flags//发送消息的方式,建议为0

);

返回:

-1:失败

0:成功

第二个参数的消息有固定的格式

4字节:表示消息的类型

若干字节:消息内容。

消息格式:(该结构体需要我们自己定义)

struct msgbuf{

long mtype; //消息类型

char mtext[1]; //消息内容

}

第三个参数:

消息的大小,不包含类型的4个字节

接收消息:

size_t msgrcv(int id ,

void * msgp ,

size_t msgsz, ,

long msgtype , //那种类型的消息

int msgflg);

返回:

-1:失败

大小:成功

删除队列:msgctl 参数和shctl一样

案例代码:

#include

#include

#include

#include

#include

#include

struct msgbuf

{

long type;

char data[32];

}

void main()

{

key_t key;

int msgid;

//1创建消息队列

key= ftok(“ . ” , 254);

if(key == -1) printf(“ftok error:%m\n”) , exit(-1);

msgid= msgget(key,IPC_CREAT | IPC_EXCL|0666);

if(msgid==-1) printf(“get error : %m\n”), exit(-1);

//2构造消息

struct msgbuf msg;

//3发送消息

for(i=1;i<=10;i++)

{

msg.type=1; //消息类型自己定义一个long类型

sprintf(msg.data , “Message:%d”,i);

msgsnd(msgid ,&msg , strlen(msg.data) , 0);

}

//4删除队列

//msgctl(msgid, IPC_RMID,0);

}

#include

#include

#include

#include

#include

#include

struct msgbuf

{

long type;

char data[32];

}

void main()

{

key_t key;

int msgid;

//1得到消息队列

key = ftok(“ . ” , 254);

if(key == -1) printf(“ftok error:%m\n”) , exit(-1);

msgid= msgget(key,0);

if(msgid== -1) printf(“get error : %m\n”), exit(-1);

//2构造消息

struct msgbuf msg;

//3接收消息

while(1)

{

bzero(&msg,sizeof(msg));

msgrcv(msgid , & msg sizeof(msg.data) , 1 , 0);

printf(“%s\n”,msg.data);

}

}

说明:如果消息队列中没有消息了读取消息的程序会阻塞等待

当程序发送消息到队列中,一个程序读取了所以消息,队列中就没有消息,就无法再读取了,只能等待在发送消息后在读取消息。

相关推荐

道友请留步首冲红卡选择 道友请留步首充选什么
365bet开户网站

道友请留步首冲红卡选择 道友请留步首充选什么

📅 06-28 👁️ 7320
出错提示
365bet体育投注地址

出错提示

📅 06-28 👁️ 5859
抖音平台的投诉率指标是怎么计算的?有哪些注意事项?
365在线体育官方网站入口

抖音平台的投诉率指标是怎么计算的?有哪些注意事项?

📅 06-28 👁️ 5053
psp 手机测评
365bet开户网站

psp 手机测评

📅 06-30 👁️ 251