• Linux IPC POSIX 消息队列


    模型:

    #include<mqueue.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    mq_open()   //创建/获取消息队列fd		
    mq_get()    //设置/获取消息队列属性	
    mq_send()/mq_receive()    //发送/接收消息	
    mq_close()      //脱接消息队列			
    mq_unlink()     //删除消息队列			
    

    POSIX mq VS Sys V mq的优势

    • 更简单的基于文件的应用接口
    • 完全支持消息优先级(优先级最终决动队列中消息的位置)
    • 完全支持消息到达的异步通知,这通过信号或是线程创建实现
    • 用于阻塞发送与接收操作的超时机制

    消息队列名

    $man mq_overview知:消息队列由一个形如'/somename'的名字唯一标识,名字字符串的最大长度不能朝着哦NAME_MAX(i.e.,255),两个进程通过使用同一个消息队列的名字来通信

    mq_open()

    //创建一个POSIX消息队列或打开一个已经存在的消息队列,成功返回消息队列描述符mqdes供其他函数使用,失败返回(mqd_t)-1设errno
    //Link with -lrt.
    mqd_t mq_open(const char *name, int oflag);
    mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr);
    

    oflag
    must include one of:

    • O_RDONLY表示以只接收消息的形式打开消息队列
    • O_WRONLY表示以只发送消息的形式打开消息队列
    • O_RDWR表示以可接收可发送的形式打开消息队列

    can be Bitwised ORed:

    • O_NONBLOCK以nonblocking的模式打开消息队列
    • O_CREAT如果一个消息队列不存在就创建它,消息队列的拥有者的UID被设为调用进程的effective UID,GID被设为调用进程的effective GID
    • O_EXCL确保消息队列被创建,如果消息队列已经存在,则发生错误

    mode如果oflag里有O_CREAT,则mode用来表示新创建的消息队列的权限
    attr如果oflag里有O_CREAT,则attr表示消息队列的属性,如果attr是NULL,则会按照默认设置配置消息队列(mq_overview(7) for details.)

    mq_setattr() / mq_getattr()

    //设置/修改 / 获取消息队列属性,成功返回0,失败返回-1设errno
    //Link with -lrt.
    int mq_setattr(mqd_t mqdes, const struct mq_attr *newattr, struct mq_attr *oldattr);
    int mq_getattr(mqd_t mqdes, struct mq_attr *attr);
    

    mqattr结构体

    struct mq_attr {
    	long mq_flags;		/* Flags: 0 or O_NONBLOCK */
    	long mq_maxmsg;		/* Max. # of messages on queue */
    	long mq_msgsize;	/* Max. message size (bytes) */
    	long mq_curmsgs;	/* # of messages currently in queue */
    };
    

    mq_send() / mq_timesend()

    //发送消息到mqdes指向的消息队列。成功返回0,失败返回-1设errno
    //Link with -lrt.
    int mq_send(mqd_t mqdes, const char *msg_ptr,size_t msg_len, unsigned int msg_prio);
    
    //如果消息队列满
    #include<time.h>		//额外的header
    int mq_timedsend(mqd_t mqdes, const char *msg_ptr,size_t msg_len, unsigned int msg_prio,const struct timespec *abs_timeout);
    

    msg_len msg_ptr指向的消息队列的长度,这个长度必须<=消息队列中消息长度,可以是0
    **msg_prio **一个用于表示消息优先级的非0整数,消息按照优先级递减的顺序被放置在消息队列中,同样优先级的消息,新的消息在老的之后,如果消息队列满了,就进入blocked状态,新的消息必须等到消息队列有空间了进入,或者调用被signal中断了。如果flag里有O_NOBLOCK选项,则此时会直接报错
    abs_timeout:如果消息队列满了,那么就根据abs_timeout指向的结构体表明的时间进行锁定,里面的时间是从970-01-01 00:00:00 +0000 (UTC)开始按微秒计量的时间,如果时间到了,那么mq_timesend()立即返回

    struct timespec {
    	time_t tv_sec;        /* seconds */
    	long   tv_nsec;       /* nanoseconds */
    };
    

    mq_receive()/mq_timedreceive()

    //从消息队列中取出优先级最高的里面的最老的消息,成功返回消息取出消息的大小,失败返回-1设errno
    //具体功能参照mq_send()/mq_timesend()
    //Link with -lrt.
    ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio);
    #include<time.h>		//额外的header
    ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio, const struct timespec *abs_timeout);
    

    mq_notify()

    //允许调用进程注册或去注册同步来消息的通知,成功返回0,失败返回-1设errno
    //Link with -lrt.
    int mq_notify(mqd_t mqdes, const struct sigevent *sevp);
    

    sevp指向sigevent的指针

    • 如果sevp不是NULL,那么这个函数就将调用进程注册到通知进程,只有一个进程可以被注册为通知进程
    • 如果sevp是NULL且当前进程已经被注册过了,则去注册,以便其他进程注册
    union sigval {         		 	/* Data passed with notification */
    	int		sival_int;         	/* Integer value */
    	void* 	sival_ptr;         	/* Pointer value */
    };
    struct sigevent {
    	int   	sigev_notify; 		/* Notification method */
    	int   	sigev_signo;  		/* Notification signal */
    	union sigval 	sigev_value;  	/* Data passed with notification */
    	void(*sigev_notify_function) (union sigval); //Function used for thread notification (SIGEV_THREAD)
    	void*	sigev_notify_attributes;	// Attributes for notification thread (SIGEV_THREAD)
    	pid_t   sigev_notify_thread_id;		/* ID of thread to signal (SIGEV_THREAD_ID) */
    };
    

    sigev_notify使用下列的宏进行配置:

    • SIGEV_NONE调用进程仍旧被注册,但是有消息来的时候什么都不通知
    • SIGEV_SIGNAL通过给调用进程发送sigev_signo指定的信号来通知进程有消息来了
    • SIGEV_THREAD一旦有消息到了,就激活sigev_notify_function作为新的线程的启动函数

    mq_close()

    //关闭消息队列描述符mqdes,如果有进程存在针对这个队列的notification request,那么也会被移除
    //成功返回0,失败返回-1设errno
    //Link with -lrt.
    int mq_close(mqd_t mqdes);
    
    //移除队列名指定的消息队列,一旦最后一个进程关闭了针对这个消息队列的描述符,就会销毁这个消息队列
    //成功返回0,失败返回-1设errno
    //Link with -lrt.
    int mq_unlink(const char *name);
    
  • 相关阅读:
    洛谷.1110.[ZJOI2007]报表统计(Multiset Heap)
    洛谷.1110.[ZJOI2007]报表统计(Multiset)
    洛谷.3809.[模板]后缀排序(后缀数组 倍增) & 学习笔记
    洛谷.2801.教主的魔法(分块 二分)
    洛谷.2709.小B的询问(莫队)
    COGS.1901.[模板][国家集训队2011]数颜色(带修改莫队)
    COGS.1822.[AHOI2013]作业(莫队 树状数组/分块)
    COGS.1689.[HNOI2010]Bounce 弹飞绵羊(分块)
    COGS.264.数列操作(分块 单点加 区间求和)
    COGS.1317.数列操作c(分块 区间加 区间求和)
  • 原文地址:https://www.cnblogs.com/xiaojiang1025/p/5937510.html
Copyright © 2020-2023  润新知