进程间通信之消息队列和信号量
来源:互联网 发布:蝙蝠侠 超人 知乎 编辑:程序博客网 时间:2024/05/20 07:20
消息队列
消息队列是IPC对象的一种,由消息队列ID来唯一标识,消息队列就是一个消息的列表。用户可以在消息队列中添加消息、读取消息。
消息队列可以安装类型来发送/接收消息。
消息队列的操作包括:创建或者打开消息队列、添加消息、读取消息、控制消息
创建或者打开消息队列:
int msgget(key_t key,int flag);
函数参数:
- key key值
- flag 消息队列访问权限
函数返回值: 成功 消息队列 ID,出错 -1;
创建的消息队列的数量会受到系统消息队列数量的限制
添加消息函数
int msgsnd(int msqid,const void * msgp,size_t size,int flag);
函数参数: - msqid: 消息队列的ID
- msgp: 指向消息的指针。常用的消息结构msgbuf如下:
struct msgbuf{ long mtype; //消息类型char mtext[N];//消息正文};
- size : 发送的消息正文的字节数
- flag :
IPC_NOWAIT : 消息没有发送完成函数也会立即返回。
0 : 直到发送完成函数才返回。
函数返回值: 成功 0,出错 -1;
读取消息函数
int msgrcv(int msgid,void *msgp,size_t size,long msgtype,int flag)
函数参数:
- msqid: 消息队列的ID号
- msgp :接收消息的缓冲区
- size :要接收消息的字节数
- msgtype:
1. 0:接收消息队列中第一个消息
2. 大于0,接收消息队列中第一个类型为 msgtyp的消息
3. 小于0,接收消息队列中类型值不小于msgtyp的绝对值且类型值又最小的消息
- flag:0,若无消息,函数会一直阻塞
- IPC_NOWAIT,若无消息,进程会立即返回ENOMSG
函数返回值: 成功,接收到的消息的长度。失败 返回-1;
控制消息使用函数:
int msgctl(int msgqid,int cmd,struct msqid_ds *buf)
函数参数 :
- msgqid 消息队列ID
- cmd:
1. IPC_STAT 读取消息队列的属性,并将其保存在buf执行的缓冲区中
2. IPC_SET 设置消息队列的属性,这个值取自buf参数
3. IPC_RMID 从系统中删除消息队列
- buf: 消息队列缓冲区
函数返回值:成功 0,失败 -1;
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#define BFUSZ 512#define TYPE 100struct msgbuf{long mtype; char mtext[BFUSZ];};int main(){int qid,len; key_t key; struct msgbuf msg; if( (key = ftok(".",'a'))== -1) { perror("ftok"); exit(-1); } if( (qid = msgget(key,IPC_CREAT|0666)) == -1) { perror("msgget"); exit(-1); } printf("opened queue%d\n",qid); if( (fgets((&msg)->mtext,BFUSZ,stdin))==NULL) { puts("no message"); exit(-1); } msg.mtype = TYPE; len = strlen(msg.mtext)+1; if( msgsnd(qid,&msg,len,0)<0) { perror("msgsnd"); exit(-1); } if( msgrcv(qid,&msg,BFUSZ,0,0)<0) { perror("msgrcv"); exit(-1); } printf("message is: %s\n",(&msg)->mtext);if(msgctl(qid,IPC_RMID,NULL)<0){ perror("msgctl"); exit(1);} return 0;}
信号量
信号灯 (semaphore) 也叫做信号量。它是不同进程间或同一进程内部不同线程间同步的机制。
信号灯种类:
- posix有名信号灯
- posix基于内存的信号灯(无名信号灯)
- System V信号灯(IPC对象)
System V信号灯是一个或者多个信号灯的集合。其中的每一个都是耽误的计数信号灯。而Posix信号灯指的是单个信号灯
System V信号灯由内核维护。主要函数semget,semop,semctl
int semget(key_t key , int nsems,int semflg);
函数参数:
- key:和信号灯集相关联的key值
- nsems:信号灯集中包含的信号灯数目
- semflg 信号灯集的访问权限 通常为IPC_CREAT|0666
函数返回值:成功 信号灯集ID
失败 -1;
int semop(int semid ,struct sembuf * opsptr,size_t nops);
函数参数:
- semid:信号灯集ID
struct sembuf{ short sem_num; //要操作的信号灯编号short sem_op; //0:等待,直到信号灯的值变为0 //1:释放资源,V操作 //-1:申请资源,P操作short sem_flg; //0,IPC_NOWAIT,SEM_UNDO };
- nops:要操作的信号灯个数
函数返回值: 成功 0,失败 -1;
int semctl(int semid,int semnum,int cmd …/* union semun arg */)
函数参数:
- semid: 信号灯集 ID
- semnum:要修改的信号灯编号
- cmd:
1. GETVAL:获取信号灯的值
2. SETVAL:设置信号灯的值
3. IPC_RMID:从系统中删除信号灯集
函数返回值:成功 0,失败 -1;
/*********************** read ************************************/
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#include <sys/shm.h>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) */};#define N 64#define READ 0#define WRITE 1void sem_init(int semid, int array[], int n){ union semun myun; int i;for (i=0; i<n; i++) { myun.val = array[i]; semctl(semid, i, SETVAL, myun); }return;}void pv(int semid, int num, int op){ struct sembuf buf;buf.sem_num = num; buf.sem_op = op; buf.sem_flg = 0; if (semop(semid, &buf, 1) < 0) { exit(0); }return;}int main(){ key_t key; int shmid, semid; char *shmaddr; int array[] = {0, 1}; if ((key = ftok(".", 's')) < 0) { perror("fail to ftok"); exit(-1); }if ((semid = semget(key, 2, 0666|IPC_CREAT|IPC_EXCL)) < 0) { if (EEXIST == errno) { semid = semget(key, 2, 0666); } else { perror("fail to semget"); exit(-1); } } else { sem_init(semid, array, 2); }if ((shmid = shmget(key, N, 0666|IPC_CREAT)) < 0) { perror("fail to shmget"); exit(-1); }shmaddr = (char *)shmat(shmid, NULL, 0);while ( 1 ) { pv(semid, READ, -1); printf("read from shm : %s", shmaddr); pv(semid, WRITE, 1); }return 0;}
/********************************** write ********************************/
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#include <sys/shm.h>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) */};#define N 64#define READ 0#define WRITE 1void sem_init(int semid, int array[], int n){ union semun myun; int i;for (i=0; i<n; i++) { myun.val = array[i]; semctl(semid, i, SETVAL, myun); }return;}void pv(int semid, int num, int op){ struct sembuf buf;buf.sem_num = num; buf.sem_op = op; buf.sem_flg = 0; semop(semid, &buf, 1);return;}int main(){ key_t key; int shmid, semid; char *shmaddr; int array[] = {0, 1}; if ((key = ftok(".", 's')) < 0) { perror("fail to ftok"); exit(-1); }if ((semid = semget(key, 2, 0666|IPC_CREAT|IPC_EXCL)) < 0) { if (EEXIST == errno) { semid = semget(key, 2, 0666); } else { perror("fail to semget"); exit(-1); } } else { sem_init(semid, array, 2); }if ((shmid = shmget(key, N, 0666|IPC_CREAT)) < 0) { perror("fail to shmget"); exit(-1); }shmaddr = (char *)shmat(shmid, NULL, 0);while ( 1 ) { pv(semid, WRITE, -1); printf("write to shm : "); fgets(shmaddr, N, stdin); if (strncmp(shmaddr, "quit\n", 5) == 0) break; pv(semid, READ, 1); } shmdt(shmaddr); shmctl(shmid, IPC_RMID, NULL); semctl(semid, 0, IPC_RMID);return 0;}
- 进程间通信之消息队列和信号量
- Linux进程间通信之信号量(semaphore)、消息队列(Message Queue)和共享内存(Share Memory) System V 进程通信方式:信号量(semaphore)、消息队列
- Linux进程间通信之信号量(semaphore)、消息队列(Message Queue)和共享内存(Share Memory)
- 【Linux】进程间通信之消息队列、信号量和共享存储
- 进程间通信之消息队列通信
- 进程间通信:管道,信号量,共享内存,消息队列
- 进程间通信:消息队列&信号量&共享内存
- Linux下进程间通信方式之管道、信号、共享内存、消息队列、信号量、套接字
- IPC通信之消息队列、信号量和共享内存
- linux进程间通信之消息队列
- 进程间通信之消息队列篇
- linux进程间通信之消息队列
- 进程间通信之消息队列
- linux进程间通信之消息队列
- Linux进程间通信之消息队列
- 进程间通信之消息队列
- 进程间通信之消息队列
- 进程间的通信之消息队列
- Java学习之路第十一天
- JAVA反射机制的一些用法
- startactivityforresult的使用,和singleTask不能使用的问题
- bzoj1497: [NOI2006]最大获利
- G
- 进程间通信之消息队列和信号量
- Javascript类型判断
- spring源码解读(1)-容器基本实现
- Instrucment初识
- Java的回调函数
- opencv: Canny边缘检测(图示+源码)
- java基础之参数和容器
- leetcode486-Predict the Winner
- Qt_ 错误:cannot open output file debug\myWidget2.exe: Permission denied问题