寒假学习 第22、23天 (linux 高级编程) 笔记总结
一组内核共享工具
ipcs 可以看到三段东西
Shared Memory Segments 共享内存
Semaphore Arrays 信号量数组,共享内存数组
Message Queues 共享消息队列
ipcrm
编程模型:
(1) 创建共享内存,得到一个ID shmget函数
int shmget(key_t key, // 保证由相同key产生的ID是唯一,可以用ftok函数参数唯一的key
size_t size, //共享内存大小
int shmflg); //创建方式 | 权限 方式:创建 IPC_CREAT 、IPC_EXCL防止覆盖 ,打开 0 | 0
key_t ftok(const char *pathname, int proj_id);
(2) 用这个ID映射成虚拟地址 (挂载) shmat函数
void *shmat(int shmid, //ID
const void *shmaddr, //指定虚拟首地址,0表示系统自动分配,用sbrk(0) 也可以
int shmflg); //挂载方式 SHM_REMAP重新映射 SHM_RDONLY 只读
返回合法地址表示成功,发现 1 表示失败
(3) 用虚拟地址访问内核共享内存
(4) 卸载虚拟地址 shmdt函数
(5) 删除共享内存 shctl函数(除了删除,还可以修改/ 获取共享内存的属性)
int shmctl(int shmid, // ID
int cmd, // 0 表示默认,读写IPC_STAT 获取 IPC_SET设置 IPC_RMID 删除共享内存
struct shmid_ds *buf);
共享内存的属性
key shmid owner perms bytes nattch status
共享内存id 内存创建者 共享内存的权限 大小 有几个进程挂载 共享内存状态
在这个共享内存上
例子1:
#include
#include
#include
#include
#include
#include
int main(int argc, const char *argv[])
{
key_t key;
int shmid;
key=ftok(".",255);
if(key==-1) printf("fork error:%m\n"),exit(-1);
shmid=shmget(key,4,IPC_CREAT|IPC_EXCL|0666);
if(shmid==-1) printf("shmget error:%m\n"),exit(-1);
return 0;
}
第一次运行生成的程序 ipcs -m 可以看到创建的共享内存
第二次运行生成的程序 就会产生错误 输出 “shmget error:File exists” 因为加了IPC_EXCL,ipcrm 删除创建的共享内存,就可以正常创建
共享
#include
#include
#include
#include
#include
#include
key_t key;
int shmid;
int *p;
void handle(int s)
{
shmdt(p);//卸载共享内存
shmctl(shmid,IPC_RMID,NULL); //删除共享内存
exit(1);
}
int main(int argc, const char *argv[])
{
signal(SIGINT,handle);
key=ftok(".",255);
if(key==-1) printf("fork error:%m\n"),exit(-1);
shmid=shmget(key,4,IPC_CREAT|IPC_EXCL|0666); //创建共享内存
if(shmid==-1) printf("shmget error:%m\n"),exit(-1);
p=shmat(shmid,0,0); //挂载共享内存
if(p==-1) printf("shmat error:%m\n"),exit(-1);
int i=0;
while(1) //访问共享内存
{
*p=i;
++i;
sleep(1);
}
shmdt(p);//卸载共享内存
shmctl(shmid,IPC_RMID,NULL); //删除共享内存
return 0;
}
#include
#include
#include
#include
#include
#include
int main(int argc, const char *argv[])
{
key_t key;
int shmid;
int *p;
key=ftok(".",255);
if(key==-1) printf("fork error:%m\n"),exit(-1);
shmid=shmget(key,4,0); //创建共享内存
if(shmid==-1) printf("shmget error:%m\n"),exit(-1);
p=shmat(shmid,0,0); //挂载共享内存
if(p==-1) printf("shmat error:%m\n"),exit(-1);
while(1)
{
printf("%d\n",*p);
sleep(1);
}
shmdt(p);//卸载共享内存
return 0;
}
编程模型:
(1)创建共享队列 / 得到队列 msgget函数
int msgget(key_t key, int msgflg); //msgflg 跟shmflg一样
(3)使用队列 (发送消息msgsnd函数 / 接受消息msgrcv函数)
发送消息
int msgsnd(int msqid, // ID
const void *msgp, //要发送的消息
size_t msgsz, //消息的长度 不包含类型的4个字节
int msgflg); //发送消息的方式,建议为0
失败返回-1,成功返回实际发送的字节数
消息有固定的格式:前面4个字节专门表示消息的类型,后面若干字节表示消息的内容。
系统没有给我们定义,要自己定义这个结构体
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
接收消息:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
(4)删除队列 msgctl 函数
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
例子:
#include
#include
#include
#include
#include
#include
struct msgbuf
{
long type;
char data[40];
};
int main(int argc, const char *argv[])
{
key_t key;
int msgid;
key=ftok(".",200);
if(key==-1) printf("ftok error:%m\n"),exit(-1);
msgid=msgget(key,IPC_CREAT|IPC_EXCL|0666); //创建消息队列
if(msgid==-1)printf("msgget error:%m\n"),exit(-1);
struct msgbuf msg;
int i;
for(i=0;i<10;i++){
bzero(msg.data,sizeof(msg.data));
msg.type=1;
sprintf(msg.data,"Message:%d",i);
msgsnd(msgid,&msg,sizeof(msg.data),0); //发送消息1
}
for(i=0;i<10;i++){
bzero(msg.data,sizeof(msg.data));
msg.type=2;
sprintf(msg.data,"Message2:%d",i);
msgsnd(msgid,&msg,sizeof(msg.data),0); //发送消息2
}
// msgctl(msgid,IPC_RMID,0); //删除队列
return 0;
}
例子2:
发送消息
#include
#include
#include
#include
#include
#include
struct msgbuf
{
long type;
char data[40];
};
int main(int argc, const char *argv[])
{
key_t key;
int msgid;
key=ftok(".",200);
if(key==-1) printf("ftok error:%m\n"),exit(-1);
msgid=msgget(key,IPC_CREAT|IPC_EXCL|0666); //创建消息队列
if(msgid==-1)printf("msgget error:%m\n"),exit(-1);
struct msgbuf msg;
int i;
for(i=0;i<10;i++){
bzero(msg.data,sizeof(msg.data));
msg.type=1;
sprintf(msg.data,"Message:%d",i);
msgsnd(msgid,&msg,sizeof(msg.data),0); //发送消息1
}
for(i=0;i<10;i++){
bzero(msg.data,sizeof(msg.data));
msg.type=2;
sprintf(msg.data,"Message2:%d",i);
msgsnd(msgid,&msg,sizeof(msg.data),0); //发送消息2
}
// msgctl(msgid,IPC_RMID,0);
return 0;
}
接收消息
#include
#include
#include
#include
#include
#include
struct msgbuf
{
long type;
char data[40];
};
int main(int argc, const char *argv[])
{
key_t key;
int msgid;
key=ftok(".",200);
if(key==-1) printf("ftok error:%m\n"),exit(-1);
msgid=msgget(key,0); //得到消息队列
if(msgid==-1)printf("msgget error:%m\n"),exit(-1);
struct msgbuf msg;
while(1)
{
bzero(&msg,sizeof(msg));
msgrcv(msgid,&msg,sizeof(msg.data),1,0); //接收消息1
printf("%s\n",msg.data);
bzero(&msg,sizeof(msg));
msgrcv(msgid,&msg,sizeof(msg.data),2,0); //接收消息2
printf("%s\n",msg.data);
}
return 0;
}