4.进程通信
1.消息队列
在终端查询消息队列 ipcs -q
在终端删除消息队列 ipcrm -q 队列ID号 {ipcrm -q key 键值}
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h>
(1)获取键值key --通过文件路径,加上proj_id组合生成键值key
key_t ftok(const char *pathname, int proj_id);
参数:pathname文件路径--文件路径必须存在 /home/gec
int proj_id---使用小于128的数据 100
一般写成key_t key = ftok(“pathname”,100);
(2)获取消息队列
int msgget(key_t key, int msgflg);
参数:key_t key---键值
int msgflg ————相当与open函数里面的O_CREAT ---IPC_CREAT|权限
返回值:返回消息队列的id号,失败返回-1
一般写成int msgid – msgget(key,IPC_CREAT|0777);
(3)读写队列
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数:int msqid ---队列id类似与文件描述符
const void *msgp发送消息内容(数据+标号)
size_t msgsz消息数据大小
int msgflg 标志一般设置0;
要发送的内容
struct msgbuf { long mtype; /* message type, must be > 0 */ char mtext[1]; /* message data */ };
一般写成msgsnd(msgid,&msgbuffer,sizeof(msgbuffer),0);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
参数:int msqid ---队列id类似与文件描述符
void *msgp保存读取的消息内容(数据+标号)
size_t msgsz 为msgp空间大小
long msgtyp 数据标志---message type
int msgflg 标志一般设置0;
一般写成msgrcv(msgid,&msgbuffer,sizeof(msgbuffer),100,0);
如果队列中没有数据就会阻塞。
(4)销毁队列
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数:int msqid 队列id号
int cmd 控制命令
struct msqid_ds *buf--有第二参数决定
删除队列:把第二个参数cmd设置为IPC_RMID,把第三个参数设置NULL
一般写成 int msgdestroy = msgctl(msgid,IPC_RMID,NULL);
magsend.c #include <stdio.h> #include <sys/types.h> #incldude <sys/ipc.h> #include <sys/msg.h> #include <stdlib.h> #include <unistd.h> int main() { //获取键值 key_t key=ftok("/tmp",100); printf("key=%d\n",key); //通过key获取消息队列 int msgid=msgget(key,IPC_CREATE|0777); if(msgid<0){ perror("创建消息队列失败\n"); return -1; } struct msgbuf{ long mtype; char mtext[128]; }msgbuffer; int i=0; while(1){ msgbuffer.mtype=100; sprintf(msgbuffer.mtext,"send data %d",i++); //往队列中发送数据 msgsend(msgid,&msgbuffer,sizeof(msgbuffer),0); sleep(1); } //销毁队列 int msgdestroy=msgctl(key,IPC_RMID,NULL); return 0; }
2.共享内存
ipcs -m查询
ipcrm -m id号 删除
头文件
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h>
(1)获取key值
int shmget(key_t key, size_t size, int shmflg);
参数:key_t key--键值
size_t size--申请共享内存大小 int size = 1920*1080*4;
int shmflg --权限,创建标准IPC_CREAT
返回:共享内存id, 失败-1
一般写成 int shmid = shmget(key,size,IPC_CREAT|0777)
(2)把内核共享空间映射到用户空间
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数:int shmid共享内存id号
const void *shmaddr,如果为NULL系统自定分配一块用户空间与内核空间映射并且返回首地址,
int shmflg --权限标准 如果第二个参数设置NULL,此参数可以设置0
返回值:成功返回映射到用户空间的首地址, 失败(void *) -1
一般写成 usigned int *mp = shmat(shmid,NULL,0);
(3)释放映射空间
int shmdt(const void *shmaddr);
一般写成 shmdt(mp);
(4)释放共享内存
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数:shmid--共享内存id
cmd是命令 IPC_RMID
buf如果是删除这里直接设置NULL
一般写成 shmctl(shmid, IPC_RMID, NULL);
shmwrite.c #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdlib.h> #include <unistd.h> int main() { //获取key值 key_t key=ftok("/tmp",100); //根据key获取共享内存 int size=1024*640*4; int shmid=shmget(key,size,IPC_CREAT|0777); //映射空间 unsigned int *mp=shmat(shmid,NULL,0); while(1){ //改变共享内存mp unsigned int coloe; scanf("%u",&color); for(int i=0;i<size/4;i++){ mp[i]=color; } } //释放映射 shmdt(mp); //删除共享内存 shmctl(shmid,IPC_RMID,NULL); }
shmshow.c #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdlib.h> #include <unistd.h> #incllude <sys/mman.h> int main() { //获取key key_t key=ftok("/tmp",100); int size=1024*640*4; int shmid=shmget(key,size,IPC_CREAT|0777); //映射空间 unisgned int *mp=shmat(shmid,NULL,0); //打开lcd int fd=open("/dev/fb0",O_RDWR); if(fd<0){ perror("open lcd fail"); } unisgned int *lcdmp=mmap(NULL,size,PORT_READ|PORT_WRITE,MAP_SHARED,fd,0); for(int i=0;i<size;i++){ lcdmp[i]=0xff0000; } while(1){ memcpy(lcdmp,mp,size); usleep(1000); } //释放映射 shmdt(mp); //删除共享内存 shmctl(shmid,IPC_RMID,NULL); }
3.信号量
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h>
(1)获取键值key
key_t ftok(const char *pathname, int proj_id);
一般用法key_t key = ftok("/tmp", 100);
(2)通过key值获取信号量
int semget(key_t key, int nsems, int semflg);
参数:key_t key键值
int nsems申请信号量个数
int semflg 创建标志,权限
返回值:成功返回信号量id,失败-1
int semid = semget(key, 2, IPC_CREAT|0777);
(3)初始化信号量
int semctl(int semid, int semnum, int cmd, ...);
参数:int semid信号量id
int semnum 要设置的信号量编号(编号从0开始)
第三个参数和第四个采参数相关联
union semun { int val; /* Value for SETVAL */ struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ unsigned short *array; /* Array for GETALL, SETALL */ struct seminfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */ };
比方说第三个参数是SETVAL,那么第四个参数就是联合体中的val成员
union semun { int val; } sval; int val = 1; sval.val = 1; int ret = semctl(semid, 0, SETVAL, val);
(4)pv操作,获取和释放资源
int semop(int semid, struct sembuf *sops, size_t nsops);
参数:int semid信号量编号
struct sembuf *sops--pv操作结构体
size_t nsops--指定第二个参数指针所指向的对象有多少个连续对象
PV操作之前先要初始化,定义一个结构体
struct sembuf { unsigned short sem_num; /* semaphore number */ short sem_op; /* semaphore operation */ 如果是p操作sem_op 为-1.如果是v操作sem_op值加1 short sem_flg; /* operation flags */ };
p操作 sem_p(semid, 0);
v操作 sem_v(semid, 1);
(5)释放信号量
int semctl(int semid, int semnum, int cmd, ...);
常用 semctl(semid, 0, IPC_RMID, NULL);
senA.c void sem_p(int semid, int num)//p操作 { struct sembuf sbuf; sbuf.sem_num = num; sbuf.sem_op = -1; sbuf.sem_flg = 0; semop(semid, &sbuf, 1); } void sem_v(int semid, int num)//v操作 { struct sembuf sbuf; sbuf.sem_num = num; sbuf.sem_op = 1; sbuf.sem_flg = 0; semop(semid, &sbuf, 1); } int main(void) { //1.获取key key_t key = ftok("/tmp", 100); //2.获取信号量 int semid = semget(key, 2, IPC_CREAT|0777); //3.初始化信号--编号为0的信号量 union semun { int val; } sval; int val = 1; sval.val = 1; int ret = semctl(semid, 0, SETVAL, val); while(1) { //4.p操作 sem_p(semid, 0); printf("A进程----操作\n"); sleep(1); //5.v操作 sem_v(semid, 1); } //释放信号量 semctl(semid, 0, IPC_RMID, NULL); }
semB.c void sem_p(int semid, int num) { struct sembuf sbuf; sbuf.sem_num = num; sbuf.sem_op = -1; sbuf.sem_flg = 0; semop(semid, &sbuf, 1); } void sem_v(int semid, int num) { struct sembuf sbuf; sbuf.sem_num = num; sbuf.sem_op = 1; sbuf.sem_flg = 0; semop(semid, &sbuf, 1); } int main(void) { //1.获取key key_t key = ftok("/tmp", 100); //2.获取信号量 int semid = semget(key, 2, IPC_CREAT|0777); //3.初始化信号--编号为0的信号量 #if 0 union semun { int val; } sval; int val = 0; sval.val = 0; int ret = semctl(semid, 1, SETVAL, val); #endif while(1) { //4.p操作 sem_p(semid, 1); printf("B进程----操作\n"); //sleep(1); //5.v操作 sem_v(semid, 0); } //释放信号量 }
PS:哪里写错了请指正,互相学习。