如何知道进程在一个空消息队列中放入一个消息?如果阻塞在msgrcv调用中,则除了等待无法做其他事情,如果给msgrcv指定非阻塞标志(IPC_NOWAIT),尽管不阻塞了,但必须持续调用该函数来确定何时有消息到达,也就是采用轮询方式(polling),Posix消息队列允许异步事件通知来通知何时有消息放入到某个空消息队列中,有2种方式:
1)产生一个信号
2)创建一个线程执行一个指定函数
这通过mq_notify建立。
union sigval


{
int sival_int;
void *sival_ptr;
};

struct sigevent


{
int sigev_notify;
int sigev_signo;
union sigval sigev_value;
void (*sigev_notify_function)(union sigval);
pthread_attr_t *sigev_notify_attributes;
};

#include "unpipc.h"

volatile sig_atomic_t mqflag;
static void sig_usr1(int signo)


{

mqflag = 1;
return;
}
int main(int argc,char** argv)


{

mqd_t mqd;
void * buff;
SSIZE_T n;
sigset_t zeromask,newmask,oldmask;
struct mq_attr attr;
struct sigevent sigev;
mqd = mq_open(argv[1],O_RDONLY|O_NONBLOCK);//打开消息队列
mq_getattr(mqd,&attr);
buff = malloc(attr.mq_msgsize);//创建接收缓冲区
sigemptyset(&zeromask);
sigemptyset(&newmask);
sigemptyset(&oldmask);
sigaddset(&newmask,SIGUSR1);
//初始化信号处理
signal(SIGUSR1,sig_usr1);
sigev.sigev_notify = SIGEV_SIGNAL;
sigev.sigev_signo = SIGUSR1;
mq_notify(mqd,&sigev);
for(;;)

{
sigprocmask(SIG_BLOCK,&newmask,&oldmask);//阻塞SIGUSR1信号
while(mqflag==0)sigsuspend(&zeromask);
mqflag = 0;
mq_notify(mqd,&sigev);
while((n=mq_receive(mqd,buff,attr.mq_msgsize,NULL))>=0)

{//循环接收数据
printf("read %ld bytes\n",(long)n);
}
sigprocmask(SIG_UNBLOCK,&newmask,NULL);
}
exit(0);
}

struct msqid_ds


{
struct ipc_perm msg_perm;
struct msg* msg_first;
struct msg* msg_last;
msgle_t msg_cbytes;
msgqnum_t msg_qnum;
msglen_t msg_qbytes;
pid_t msg_lspid;
pid_t msg_lrpid;
time_t msg_stime;
time_t msg_rtime;
time_t msg_ctime;
};

msgget创建一个新的消息队列或访问一个已经存在的消息队列
msgsnd发送一个消息,消息是下面这样的结构体:
struct msgbuf


{
long mtype;//消息类型
char mtext[1];//消息数据
};

但这个预定的结构一般无法满足自己的需求,因此一般定义自己的结构
typedef struct my_msgbuf


{
long mtype;
int16_t mshort;//消息数据起始
char mchar[MY_DATA];
}Message;

发送数据时可以指定flag为IPC_NOWAIT,这个标志使得msgsnd调用非阻塞,
调用msgrcv函数时,若type指定为0,则返回消息队列第一个消息,若type小于0,则返回类型值小于或等于type绝对值的消息中类型值最小的
第一个消息
使用两个消息队列来实现前面的客户—服务器例子,一个队列用于从客户方到服务器的消息,一个队列用于从服务器到客户的消息。

#include "unpipc.h"
#define MQ_KEY1 1234L
#define MQ_KEY2 2345L

int main()


{
int readid,writeid;
readid = msgget(MQ_KEY1,SVMSG_MODE|IPC_CREATE);
writeid = msgget(MQ_KEY2,SVMSG_MODE|IPC_CREATE);
server(readid,writeid);
exit(0);
}

int main()


{
int readid,writeid;
readid = msgget(MQ_KEY2,0);
writeid = msgget(MQ_KEY1,0);
client(readid,writeid);
//删除消息队列
msgctl(readid,IPC_RMID,NULL)
msgctl(writeid,IPC_RMID,NULL);
exit(0);

}

第8节使用一个队列来实现单服务器,多客户端的通信,但互斥,死锁可能存在,另一种思路就是为每个实体单独设置一个私有队列,消息都发送到自己的队列中,也只从自己的队列中取消息.
System V的消息队列比Posix消息队列差多了,要使用select模型同时处理网络连接和IPC连接时,必须产生子进程,使用管道作为中介,另外一个弱点是无法Peek一个消息.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述
2006-05-27 《Java编程思想》读书笔记(2)