什么是消息队列
(1)消息队列提供了一种从一个进程向另一个进程发送数据块的方法。
(2)消息队列的生命周期不是随进程,而是随内核。
(3)消息队列属于操作系统。
2.消息队列的函数
(1.)创建新消息队列或取得已存在消息队列
原型:int msgget(key_t key, int msgflg);
参数:
key:可以认为是一个端口号,也可以由函数ftok生成。
msgflg:
IPC_CREAT 如果IPC不存在,则创建一个IPC资源,否则打开操作。
IPC_EXCL:单独使用没有意义。如果将IPC_CREAT和IPC_EXCL标志一起使,不存在将会创建,存在则会出错返回。
(2.)向队列读/写消息
原型:
msgrcv从队列中取用消息:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
msgsnd将数据放到消息队列中:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数:
msqid:消息队列的标识码
msgp:指向消息缓冲区的指针,此位置用来暂时存储发送和接收的消息,是一个用户可
定义的通用结构,形态如下:
struct msgstru{
long mtype; //大于0
char mtext[用户指定小];
};
msgsz:消息的小。
msgtyp:从消息队列内读取的消息形态。如果值为零,则表示消息队列中的所有消息都会被读取。
msgflg:用来指明核心程序在队列没有数据的情况下所应采取的行动。如果msgflg和常
数IPC_NOWAIT合用,则在msgsnd()执行时若是消息队列已满,则msgsnd()将不会阻塞,而
会立即返回-1,如果执行的是msgrcv(),则在消息队列呈空时,不做等待马上返回-1,并设定
错误码为ENOMSG。当msgflg为0时,msgsnd()及msgrcv()在队列呈满或呈空的情形时,采取
阻塞等待的处理模式。
(3.)设置消息队列属性
原型:int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );
参数:msgctl 系统调用对 msgqid 标识的消息队列执行 cmd 操作,系统定义了 3 种 cmd 操作
: IPC_STAT , IPC_SET , IPC_RMID
IPC_STAT : 该命令用来获取消息队列对应的 msqid_ds 数据结构,并将其保存到 buf 指
定的地址空间。
IPC_SET : 该命令用来设置消息队列的属性,要设置的属性存储在buf中。
IPC_RMID : 从内核中删除 msqid 标识的消息队列。
写一个消息队列程序:
comm.h
comm.c
client.c
server.c
效果图:
3.信号量:信号量的本质是一种数据操作锁,它本身不具有数据交换的功能,而是通过控制其他的
通信资源(文件,外部设备)来实现进程间通信,它本身只是一种外部资源的标识。信号
量在此过程中负责数据操作的互斥、同步等功能。当请求一个使用信号量来表示的资源时,进程需要先读取信号量的值来判断资源是否可用。大于0,资源可以请求,等于0,无资源可用,进程会进入睡眠状态直至资源可用。当进程不再使用一个信号量控制的共享资源时,信号量的值+1,对信号量的值进行的增减操作均为原子操作,这是由于信号量主要的作用是维护资源的互斥或多进程的同步访问。而在信号量的创建及初始化上,不能保证操作均为原子性。
4.为什么使用信号量
为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区域。临界区域是指执行数据更新的代码需要独占式地执行。而信号量就可以提供这样的一种访
问机制,让一个临界区同一时间只有一个线程在访问它, 也就是说信号量是用来调协进程
对共享资源的访问的。其中共享内存的使用就要用到信号量。
5.相关函数
信号量的相关函数与消息队列的函数都比较相似,在进行p,v运算时,用到结构体sembuf
struct sembuf
{
unsigned short sem_num ;//信号量的总数相当于从0开始的一个数组,这里的_num表示总个数
short sem_op ;//-1:p运算 1:v运算
short sem_flg = 0;//通常为SEM_UNDO,使操作系统跟踪信号,并在进程没有释放该信号量而终止时,操作系统释放信号量
};
6.信号量工作原理
由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:
P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行
V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂
起,就给它加1.