1. 程式人生 > >UNP(卷2:程序間通訊)—— 第5章:Posix訊息佇列

UNP(卷2:程序間通訊)—— 第5章:Posix訊息佇列

Posix訊息佇列 和 System V 訊息佇列的主要差別

  • 對POSIX訊息佇列的讀總是返回最高優先順序的最早訊息,對System V訊息佇列的讀則可以返回任意指定優先順序的訊息。
  • 當往一個空佇列放置一個訊息時,Posix訊息佇列允許產生一個訊號或啟動一個執行緒,System V訊息佇列則不提供類似的機制。

佇列中的每個訊息都具有如下屬性

  • 一個無符號整數優先順序(Posix),或 一個長整數型別(System V);
  • 訊息的資料部分長度(可以為0)
  • 資料本身(如果長度大於0)

mq_open、mq_close、mq_unlink

#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <mqueue.h>

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);
                             // 返回:成功則為訊息佇列描述符,出錯為-1
oflag:O_RDONLY、O_WRONLY、O_RDWR;按位或O_CREAT、O_EXCL、O_NONBLOCK

在建立一個新佇列時,mode和attr引數是需要的。如果attr為NULL,就使用預設屬性。

#include <mqueue.h>

int mq_close(mqd_t mqdes);

int mq_unlink(const char *name);
                             // 返回:成功則為0,出錯則為-1
呼叫mq_close,不再使用該描述符,但其訊息佇列並不從系統中刪除。

要從系統中刪除,必須呼叫mq_unlink

描述符的開啟,有一個引用計數器,當一個訊息佇列的計數仍大於0時,其name就能刪除,但是該佇列的析構要到最後一個mq_close發生時才進行。

例子:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#include <errno.h>

#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

int main(int argc, char **argv)
{
    printf("argc = %d\n", argc);
    int    c, flags;
    mqd_t  mqd;

    flags = O_RDWR | O_CREAT | O_EXCL;
    while ( (c = getopt(argc, argv, "e")) != -1 ) {
        switch (c) {
        case 'e':
            flags |= O_EXCL;
            break;
        }
    }
    if (optind != argc - 1) {
        printf("usage: mqcreate [-e] <name>\n");
        return -1;
    }

    mqd = mq_open(argv[optind], flags, FILE_MODE, NULL);
    if (mqd == -1) {
        printf("mq_open failed!---[errno = %d]\n", errno);
        return -1;
    }

    mq_close(mqd);

    exit(0);
}

$ ./mqcreate /1234.mq

一直不清楚引數name的要求,通過檢視man mq_overview得知:

Each  message queue  is  identified  by  a  name  of the form /somename;

所以像 /tmp/1234.mq 是不正確的。

生成的訊息佇列檔案在/dev/mqueue/目錄下。

mq_getattr、mq_setattr

#include <mqueue.h>

int mq_getattr(mqd_t mqdes, struct mq_attr *attr);

int mq_setattr(mqd_t mqdes, const struct mq_attr *newattr, struct mq_attr *oldattr);
                             // 返回:成功則為0,出錯則為-1
每個訊息佇列有四個屬性,mq_getattr返回所有這些屬性,mq_setattr設定其中某個屬性。
struct mq_attr {
    long mq_flags;       /* Flags: 0 or O_NONBLOCK */
    long mq_maxmsg;      /* Max number of messages allowed on queue */
    long mq_msgsize;     /* Max size of message (bytes) */
    long mq_curmsgs;     /* number of messages currently in queue */
};
呼叫mq_open,可指定mq_maxmsg和mq_msgsize屬性,mq_open會忽略另外兩個成員。

呼叫mq_setattr,只設置或清楚非阻塞標誌。mq_maxmsg和mq_msgsize只能在建立佇列時設定mq_curmsgs只能獲取,不能設定。

若oldattr非空,則先前的屬性將返回到該結構體中。

mq_send、mq_receive

往佇列中放置一個訊息,從佇列中取走一個訊息。

每個訊息有一個優先順序,它是小於MQ_PRIO_MAX的無符號整數。Posix要求這個上限至少為32。

mq_receive總是返回所指定佇列中最高優先順序的最早訊息,而且該優先順序能隨該訊息的內容及其長度一同返回。

#include <mqueue.h>

int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio);
                                                                                       // 返回:若成功則為0,出錯為-1
ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio);
                                                                                       // 返回:若成功則為訊息中位元組數,出錯為-1

#include <time.h>
#include <mqueue.h>

int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout);
ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio, const struct timespec *abs_timeout);

mq_receive的msg_len的值不能小於mq_msgsize,否則返回EMSGSIZE錯誤。

mq_send的prio引數是待發送訊息的優先順序。其值必須小於MQ_PRIO_MAX。

訊息佇列限制:

mq_maxmsg

mq_msgsize

MQ_OPEN_MAX:一個程序能夠同時擁有開啟著訊息佇列的最大數目。(Posix要求至少為8)

MQ_PRIO_MAX:任意訊息的最大優先順序值加1(Posix要求至少為32)

mq_notify

#include <mqueue.h>

int mq_notify(mqd_t mqdes, const struct sigevent *sevp);
                                                          // 返回:若成功則為0,出錯則為-1
Posix訊息允許非同步事件通知(asynchronous event notification),以告知何時有一個訊息放置到了某個空訊息佇列中。這種通知有兩種方式選擇:
  • 產生一個訊號;
  • 建立一個執行緒來執行一個指定的函式。

這種通知通過呼叫mq_notify建立。該函式為指定佇列建議或刪除非同步事件通知。

union sigval {
    int    sival_int;    /* Integer signal value. */
    void  *sival_ptr;    /* Pointer signal value. */
};

struct sigevent {
    int         sigev_notify;              /* Notification type. */
    int         sigev_signo;              /* Signal number. */
  union sigval     sigev_value;              /* Signal value. */
  void        (*sigev_notify_function)(union sigval); /* Notification function. */
  pthread_attr_t      *sigev_notify_attributes;             /* Notification attributes. */
};

(1).如果notification引數為非空,那麼當前程序希望在有一個訊息到達所指定的先前為空的對列時得到通知。 (2).如果notification引數為空,而且當前程序被註冊為接收指定佇列的通知,那麼已存在的註冊將被撤銷。 (3).任意時刻只有一個程序可以被註冊為接收某個給定佇列的通知。 (4).當有一個訊息到達先前為空的訊息佇列,而且已有一個程序被註冊為接收該佇列的通知時,只有在沒有任何執行緒阻塞在該佇列的mq_receive呼叫中的前提下,通知才會發出。即說明,在mq_receive呼叫中的阻塞比任何通知的註冊都優先。 (5).當前通知被髮送給它的註冊程序時,其註冊幾倍撤銷。該程序必須再次呼叫mq_notify以重新註冊。


沒有列在該表中的函式不可以從訊號處理程式中呼叫。

POSIX實時訊號

訊號可劃分為兩個大組:
0、其值在SIGRTMIN和SIGRTMAX之間(包括兩者在內)的實時訊號。POSIX要求至少提供RTSIG_MAX種實時訊號,而該常值的最小值為8.
1、所有其他訊號:SIGALRM、SIGINT、SIGKILL等等。

當接收到某個訊號的程序其sigaction呼叫中是否指定了新的SA_SIGINFO標誌,會造成以下的差異:

0、SA_SIGINFO指定時:SIGRTMIN到SIGRTMAX訊號的實時行為有保證 而所有其他訊號的行為沒有保證 

1、SA_SIGINFO沒有指定時所有訊號的實時行為都沒有保證。

就這種情況來看,若需要實時行為,我們就得使用SIGRTMIN和SIGRTMAX之間的新的實時訊號,而且在安裝訊號處理程式時必須給sigaction指定SA_SIGINFO標誌。


術語實時行為(realtime behavior)隱含著如下特徵:
0、訊號是排隊的。也即是說若同一訊號產生了三次,它就遞交三次。另外,一種給定訊號的多次發生以先進先出(FIFO)順序排隊。對於不排隊的訊號來說,產生了三次的某種訊號可能只遞交一次。
1、當有多種SIGRTMIN到SIGRTMAX範圍內的解阻塞訊號排隊時,值較小的訊號先於值較大的訊號遞交 。即是說:SIGRTMIN比值為SIGRTMIN+1的訊號“更為優先”。
2、當某個非實時訊號遞交時,傳遞給它的訊號處理程式的唯一引數是該訊號的值。實時訊號比其他訊號傳遞更多的資訊。

可以通過設定 SA_SIGINFO標誌安裝的任意實時訊號的訊號處理程式宣告如下:

typedef struct { 
           int           si_signo;  /* Signal number.*/
           int           si_code;   /* Signal code. */
           int           si_errno;  /* If non-zero, an errno value associated with this signal, as described in <errno.h>. */
           pid_t         si_pid;    /* Sending process ID. */
           uid_t         si_uid;    /* Real user ID of sending process. */
           void         *si_addr;   /* Address of faulting instruction. */
           int           si_status; /* Exit value or signal. */
           long          si_band;   /* Band event for SIGPOLL. *、
           union sigval  si_value;  /* Signal value. */
} siginfo_t;



相關推薦

UNP2程序通訊—— 5Posix訊息佇列

Posix訊息佇列 和 System V 訊息佇列的主要差別: 對POSIX訊息佇列的讀總是返回最高優先順序的最早訊息,對System V訊息佇列的讀則可以返回任意指定優先順序的訊息。當往一個空佇列放置一個訊息時,Posix訊息佇列允許產生一個訊號或啟動一個執行緒,Sys

程序通訊的方式——訊號、管道、訊息佇列、共享記憶體

多程序: 首先,先來講一下fork之後,發生了什麼事情。 由fork建立的新程序被稱為子程序(child process)。該函式被呼叫一次,但返回兩次。兩次返回的區別是子程序的返回值是0,而父程序的返回值則是新程序(子程序)的程序 id。將子程序id返回給父程序的理由是

嵌入式Linux併發程式設計,程序通訊方式,System V IPC,訊息佇列,開啟/建立msgget(), 傳送訊息msgsnd(),格式,接收訊息msgrcv(),控制訊息佇列 msgctl()

文章目錄 1,訊息佇列 2,訊息佇列結構 3,訊息佇列使用步驟 3.1,開啟/建立訊息佇列 msgget() 3.1.1,開啟/建立訊息佇列---示例msgget() 3.2,向訊息佇列傳送訊息 msgs

【linux開發】程序通訊命名管道-共享記憶體-記憶體對映-訊息佇列-訊號量

程序間通訊命名管道-共享記憶體-記憶體對映-訊息佇列-訊號量  在Unix平臺上,建立命名管道是建立了一個fifo檔案,和在shell下面用mkfifo命令的效果是一樣的。看起來這個管道檔案就是一個普通的檔案系統瓜掛載點,但是它只不過是作為一個名稱存在,實際的內容是一塊系統

【算法競賽入門經典—訓練指南】學習筆記含例題代碼與思路實用數據結構

其他 ont freopen data 依然 插入 else if swa urn 值得註意的是,本章雖然依然有很多不錯的思想和題目,但並不建議初學知識點時從這裏入門。並不是因為題目難,而是講解並沒有看網上其他博客來的清楚。 本章缺少的重要科技:\(Link-Cut-Tre

Linux程序通訊匿名管道命名管道共享記憶體,訊息佇列,訊號量

目錄 程序間通訊的介紹 管道 匿名管道 原理: 程式碼實現 匿名管道特性 實現管道符 |  命名管道 命名管道特性 程式碼實現 管道讀寫規則 作業系統中ipc的相關命令 共享記憶體(重點) 生命週期: 程式碼實現 程式碼實現獲

程序程序通訊 —— Queue佇列和Pipe管道

目錄 程序間通訊 佇列  概念介紹 方法介紹 程式碼例項 生產者消費者模型 JoinableQueue([maxsize])  管道(瞭解) 程序間通訊 IPC(Inter-Process Communication) 佇列&nbs

程序學習程序通訊基礎知識篇

system v IPC 函式一覽圖 key值 和 id值 其他IPC的***get函式也是這樣的原理; 檢視 IPC(訊息佇列、共享記憶體、訊號燈) 命令列引數 一、 ipcs 檢

每天3分鐘作業系統修煉祕籍17程序通訊(3)套接字

點我檢視祕籍連載 套接字 套接字(Socket)用於協調不同計算機上的程序間通訊,也就是基於網路的通訊。當然,也可以在本機上使用套接字進行程序間的通訊。 套接字通訊的方式非常多,有Unix域套接字、TCP套接字、UDP套接字、鏈路層套接字等等。但最常用的肯定是TCP套接字。所以,這裡介紹下TCP Socket

java程序通訊的方式

程序間通訊的方式有哪些,各有什麼優缺點: 1)管道:管道是一種半雙工的通訊方式,資料只能單向流動,而且只能在具有親緣關係的程序之間使用。程序的親緣關係通常是指父子程序關係。 2)有名管道(FIFO):有名管道也是半雙工的通訊方式,但是允許在沒有親緣關係的程序之間使用,管道是先進先出的通訊方式

Linux程序通訊之管道通訊詳解

        在學習程序的時候,我們瞭解到了程序的獨立性:程序之間是相互獨立的,每個程序有自己的虛擬地址空間,並且虛擬地址空間通過頁表的對映,對映到屬於自己的實體記憶體上。並且各個程序之間互相不影響,執行自己的程式碼。    

一個小Demo來理解關於IPC程序通訊中的aidl

專案地址: Server端程式碼:Server端程式碼連結 Client端程式碼:Client端程式碼連結 1、IPC的基本要求 IPC(Inter-Process Communication)程序間通訊是要在兩個相互獨立的程序之間進行資訊的傳遞,在Android中每個程序都會被分配

android IPC程序通訊機制

一、多程序的情況 1.       一個應用因為某些原因自身需要採用多程序模式實現。 可能是某些模組由於特殊原因需要執行在單獨的執行緒中;或是為了增大一個應用可以使用的記憶體空間。android對單個應用使用的最大記憶體做了限制,早期一些版本是16M,不同裝置有不同的大小。

筆記程序通訊——同步(互斥鎖、讀寫鎖、條件變數、訊號量以及Linux中的RCU

1.互斥鎖 多個執行緒的IPC,需要同步,同步有隱式的和顯示的: 比如unix提供的管道和FIFO,由核心負責同步,比如read發生在write之前,那麼read就會被核心阻塞,這中同步是由核心負責的,使用者不會感知。 但如果使用共享區作為生產者和消費者之間的IPC,那麼程

談談Android的IPC程序通訊機制

一說明  Android系統最常見也是初學者最難搞明白的就是Binder了,很多很多的Service就是通過Binder機制來和客戶端通訊互動的。所以搞明白Binder的話,在很大程度上就能理解程式執行的流程。 我們這裡將以MediaService的例子來分析Binder的

Android程序通訊互動

Intent 的 ComponentName Intent作為我們最常用的資料傳輸渠道,特別是通過Intent開啟一個Activity,想必每個人都不會陌生。通常我們用到的都是通過Intent開啟同一個程序(App)內部的Activity,如果想實現

JUC二、執行緒通訊

兩個執行緒,一個執行緒列印1-52,另一個列印字母A-Z列印順序為12A34B...5152Z, 要求用執行緒間通訊 1.syn

AbpZero之企業微信---登錄拓展第三方auth授權登錄---三步需要註意事項

login eat exce sync private open 生成 isp lose 1、AbpZero的auth登錄會在數據庫中的AbpUserLogins表會根據你登錄的ProviderKey和Provider來生成生成一條記錄,ProviderKey在表中是唯一的

5作為Web應用屬性和監聽者/5.2 Servlet監聽器

監聽器介面彙總 上下文相關 初始化完成或者銷燬監聽器:ServletContextListener 新增、刪除或者替換一個屬性監聽器:ServletContextAttributeListener(屬性相關) 會話有關:

5座標和依賴/5.2 座標詳解

座標詳解 座標內容包括 groupid:必選 概念:通用用java包的形式表示(也就是.(點)表示法),內容一般是組織或者公司下的某個專案 例如:org.sonatype.nexus,org.sonatype 為非盈利組織