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結構體code

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);
相關文章
相關標籤/搜索