linux之共享消息队列

linux进程,线程之间通信方式之一,共享队列

1.概念

   在系统内核中,实现了一种链表结构的共享队列,各节点挂接可能不是同一种类型的数据结构信息,但是在每个结构数据都是指明该消息的类型的,如下结构:

typedef struct msg {
    long type; // 消息的类型
    char name[33];
}MSG;

如上结构,type表示的是当前消息的类型,整形数标记。这样做的好处是,使用者可以根据自己实际业务情况,设置自定义的数据格式,方便灵活。

2.共享队列的方法介绍以及使用举例:

 int msgget(key_t key, int msgflg);

返回值: 成功返回队列的id,失败返回-1,msgflag的取值如下所示:

key:通过fotk方法生成对应的key,用于创建队列时的标示参数。( key_t ftok(const char *pathname, int proj_id); pathname:路径,proj_id可自己指定)

msgflag:该单数去|运算结果,

                 IPC_CREAT:获取一个队列的,不存在就创建

                 IPC_EXCL:跟创建配和使用,在获取队列id时,队列存在直接返回错误。
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

 返回值:0 表示成功,-1 失败并设置 errno。

msgid:msgget方法返回的消息id

msgp;具体消息结构,

msgsz:具体消息的大小(字节)

msgflag:可选项,具体区分:

    0:当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列或者消息队列被删除。
    IPC_NOWAIT:当消息队列满了,msgsnd函数将不会等待,会立即出错返回EAGAIN

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
                      int msgflg);
 ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
                      int msgflg);

  msgid:消息队列id

  msgp:出参,消息结构,

  msgsz;消息的大小。

 msgtyp: 分为三种情况,如下:

== 0:返回队列中第一个元素。

> 0:返回类型为msgtyp的第一个消息。

< 0 返回队列中消息类型值小于等于type绝对值的消息,如果这种消息有若干个,则取类型值最小的消息

 flag:可以为0、IPC_NOWAIT、IPC_EXCEPT

        为0时,阻塞式接收消息,没有该类型的消息msgrcv函数一直阻塞等待

        为IPC_NOWAIT时,如果没有返回条件的消息调用立即返回,此时错误码为ENOMSG

        为IPC_EXCEPT时,与msgtype配合使用返回队列中第一个类型不为msgtype的消息,可用于过滤掉不需要的消息.

返回值:成功返回消息数据部分的长度;错误返回-1

 

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

msgid:队列id

cmd:操作处理的命令,如下:

    IPC_STAT:取此队列的msqid_ds结构,并将它存放在buf指向的结构中

    IPC_RMID;删除消息队列。

    IPC_SET:改变消息队列的状态,把buf所指的msqid_ds结构中的uid、gid、mode复制到消息队列的msqid_ds结构内。(内核为每个消息队列维护着一个结构,结构名为msqid_ds,里面存放着消息队列的大小,pid,存放时间等一些参数)具体结构类型见如下:



 struct msqid_ds {
               struct ipc_perm msg_perm;     /* Ownership and permissions */
               time_t          msg_stime;    /* Time of last msgsnd(2) */
               time_t          msg_rtime;    /* Time of last msgrcv(2) */
               time_t          msg_ctime;    /* Time of last change */
               unsigned long   __msg_cbytes; /* Current number of bytes in
                                                queue (nonstandard) */
               msgqnum_t       msg_qnum;     /* Current number of messages
                                                in queue */
               msglen_t        msg_qbytes;   /* Maximum number of bytes
                                                allowed in queue */
               pid_t           msg_lspid;    /* PID of last msgsnd(2) */
               pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
           };

 struct ipc_perm {
               key_t          __key;       /* Key supplied to msgget(2) */
               uid_t          uid;         /* Effective UID of owner */
               gid_t          gid;         /* Effective GID of owner */
               uid_t          cuid;        /* Effective UID of creator */
               gid_t          cgid;        /* Effective GID of creator */
               unsigned short mode;        /* Permissions */
               unsigned short __seq;       /* Sequence number */
           };

3,消息队列使用举例。

发送方:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#define MSG_QUEUE_NAME "wechat"
 
// 消息结构
typedef struct msg {
    long type; // 消息的类型
    char name[128];
}MSG;
 
typedef struct threadArgs {
    long type;
    int msgId;
}ThreadArgs;
 
void * threadProcess(void* args) {
 
        ThreadArgs pargs = *(ThreadArgs*)(args);
        printf("我是线程,我的ID = %lu - %lu\n", pthread_self(),pargs.type);
        int count = 0;
        for(;;){
            
            MSG msg;
            msg.type = pargs.type; // 消息类型
            sprintf(msg.name,"Msg type is %lu,number is %d,threadId %lu",msg.type,count++,pthread_self());
            int ret = msgsnd(pargs.msgId, (void*)&msg, sizeof(msg),IPC_NOWAIT); // 不等待直接写入队列,如果队列满,直接返回队列满错误编码
            if(ret == -1) {
                printf("add msg is failed,is,errno =  %d\n",errno);     
                sleep(1);   
                continue;
            }
            printf("add msg type is %s\n",msg.name);
            sleep(1);
        }
        printf("thread end --->%d",pargs.type);
}
 
int main() {
 
    key_t key;
    key = ftok("./",100);
    if(key == -1) {
        perror("ftok");
        return -1;
    }
    int msgPID;
    msgPID = msgget(key,IPC_CREAT|0666); // 获取一个队列
    if(msgPID == -1) {
       perror("msgget");
       return -1;
    }    
    pthread_t pidArr[3];
    for(int i = 0;i < 3;++i){
        ThreadArgs args;
        args.type = i + 1; // 消息类型
        args.msgId = msgPID; // 队列id
        printf("msgid is %d-%d\n",args.type,args.msgId);
        int ret = pthread_create(&pidArr[i],NULL,threadProcess,(void*)&args);//如果穿参数,考虑变量共享的情况。避免出现意想不到的结构。
        if (ret != 0){
            continue;
            sleep(1);
        }
    }
 
    for(int i = 0;i < 1;++i){
        pthread_join(pidArr[i],NULL);
    }
     while(true) {
        sleep(1);
    }
 
    // 结束删除掉该队列
    struct msqid_ds buff;
    int ret = msgctl(msgPID,IPC_RMID,&buff);
    if (ret == -1){
        return -1;
    }
    return 0;
}

接收方:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
 
#define THR 3
typedef struct msg {
    long type;
    char name[128];
}MSG;
 
typedef struct threadArgs {
    long type;
    int msgId;
}ThreadArgs;
 
void * threadProcess(void* args) {
    ThreadArgs pargs = *(ThreadArgs*)(args);
    long int msgtype = pargs.type;
    while(true) {
        MSG msg;
        int ret = msgrcv(pargs.msgId,(void*)&msg,sizeof(msg),msgtype,0);
        if(ret == -1){
            continue;
            sleep(1);
        }
        printf("_+_+ %s\n",msg.name);
        sleep(1);
    }
 
}
 
int main(){
 
    long int msgtype = 1; 
    key_t key;
    key = ftok("./",100);
    if(key == -1) {
        perror("ftok");
        return -1;
    }
    int msgid = msgget(key,IPC_CREAT|0666);
    if (msgid == -1){
        return -1;
    }
 
    pthread_t pidArr[3];
    for(int i = 0;i < THR;++i){
        ThreadArgs args;
        args.type = i + 1; // 制定消息类型
        args.msgId = msgid; // 队列id
        int ret = pthread_create(&pidArr[i],NULL,threadProcess,(void*)&args);
        // printf("create a thread is %d\n",i);
        if (ret != 0){
            continue;
        }
    }
 
    for(int i = 0;i < THR;++i){
        pthread_join(pidArr[i],NULL);
    }
    while(true) {
        sleep(1);
    }
    return 0;
}

 
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值