寒假学习 第22、23天 (linux 高级编程) 笔记总结
一、基于内存的通信
一组内核共享工具
ipcs 可以看到三段东西
Shared Memory Segments 共享内存
Semaphore Arrays 信号量数组,共享内存数组
Message Queues 共享消息队列
ipcrm
1.普通的父子进程之间的匿名内存共享映射
2.内核共享内存(无序)
编程模型:
(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 <stdio.h> #include <string.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <sys/shm.h> 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 删除创建的共享内存,就可以正常创建
例子2:
共享
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <sys/shm.h> 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 <stdio.h> #include <string.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <sys/shm.h> 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; }
3.内核共享队列(有序)
编程模型:
(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 <stdio.h> #include <unistd.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdlib.h> #include <string.h> 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 <stdio.h> #include <unistd.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdlib.h> #include <string.h> 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 <stdio.h> #include <unistd.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdlib.h> #include <string.h> 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; }
Android Studio 中提示 Private field 'mType' is assigned but never accessed 的原因