【IPC通訊】Posix消息隊列使用異步事件通知

mq_notify()函數爲指定隊列創建或刪除異步事件通知,創建通知即某空消息隊列中若有新的消息,會發送一個信號或建立一個線程來執行指定的函數。shell

#include <mqueue.h>
int mq_notify(mqd_t mqdes, const struct sigevent *notification);
成功返回0,出錯則爲-1

給出struct sigevent定義:

union signal
{
    int  sival_int;  /*整數值*/
    void *sival_ptr; /*指針值*/
};

struct sigevent
{
    int sigev_notify; /*通知類型:SIGEV_NONE、SIGEV_SIGNAL、SIGEV_THREAD*/
    int sigev_signo; /*信號值*/
    union sigval sigev_value; /*傳遞給信號處理函數或線程的信號值*/
    void (*sigev_notify_function)(union sigval); /*線程處理函數*/
    pthread_attr_t *sigev_notify_attributes; /*線程屬性*/
};

下面給出示例代碼:

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


mqd_t mqd;
struct mq_attr attr;
struct sigevent sigev;
char *ptr;
unsigned int prio;
size_t n;
int rc;

void sig_usr1(int signo);

/*讀取某消息隊列,消息隊列名經過參數傳遞*/
/*當有消息放置到某個空的隊列中時產生SIGUSR1信號*/
int main(int argc, char *argv[])
{
    if(argc != 2)
    {
        printf("Usage: mqnotifysig1 <name>\n");
        exit(1);
    }

    /*只讀模式打開消息隊列*/
    mqd = mq_open(argv[1], O_RDONLY);
    if(mqd < 0)
    {
        perror("打開消息隊列失敗");
        exit(1);
    }

    // 取得消息隊列屬性,根據mq_msgsize動態申請內存
    rc = mq_getattr(mqd, &attr);
    if(rc < 0)
    {
        perror("取得消息隊列屬性失敗");
        exit(1);
    }

    /*動態申請保證能存放單條消息的內存*/
    ptr = calloc(attr.mq_msgsize, sizeof(char));
    if(NULL == ptr)
    {
        printf("動態申請內存失敗\n");
        mq_close(mqd);
        exit(1);
    }

    //註冊信號函數
    signal(SIGUSR1, sig_usr1);
    sigev.sigev_notify = SIGEV_SIGNAL;
    sigev.sigev_signo = SIGUSR1;

    //註冊通知
    rc = mq_notify(mqd, &sigev); // 讀取前須要再次註冊
    if(rc < 0)
    {
        perror("通知註冊失敗");
        mq_close(mqd);
        free(ptr);
        exit(1);
    }

    for(;;)
    {
        pause();
    }

    return 0;
}

void sig_usr1(int signo)
{
    rc = mq_notify(mqd, &sigev); // 讀取前須要再次註冊
    if(rc < 0)
    {
        perror("通知註冊失敗");
        mq_close(mqd);
        free(ptr);
        exit(1);
    }

    /*接收一條消息*/
    n = mq_receive(mqd, ptr, attr.mq_msgsize, &prio);
    if(n < 0)
    {
        perror("讀取失敗");
        mq_close(mqd);
        free(ptr);
        exit(1);
    }
    printf("讀取 %ld 字節\n優先級爲 %u\n", (long)n, prio);
}

編譯並執行:

[infor@s123 PosixMq]$ gcc -o mqnotifysig1 mqnotifysig1.c -lrt
[infor@s123 PosixMq]$ ./mqnotifysig1 /tmp

此時消息隊列內沒有消息,程序進入睡眠,等待信號到來。再開啓一個終端,經過另外的程序往消息隊列寫消息:

[infor@s123 PosixMq]$ ./sendmq /tmp 200 16
[infor@s123 PosixMq]$ ./sendmq /tmp 100 17
[infor@s123 PosixMq]$ ./sendmq /tmp 50 18

能夠看到先前的程序:

[infor@s123 PosixMq]$ gcc -o mqnotifysig1 mqnotifysig1.c -lrt
[infor@s123 PosixMq]$ ./mqnotifysig1 /tmp
讀取 200 字節
優先級爲 16
讀取 100 字節
優先級爲 17
讀取 50 字節
優先級爲 18

mq_notify函數使用規則:

一、若是mq_notify()的notification參數非空,則代表將當前進程註冊爲接收某隊列的通知;
二、若是mq_notify()的notification參數爲空,則代表以前已存在的註冊將被撤消;
三、一個消息隊列任意時刻只能由一個進程註冊;
四、若有其餘進程mq_receive阻塞在該消息隊列時,信號不會發出,即mq_receive調用優先級更高;
五、通知被髮送給註冊進程時,註冊即被撤消,須從新註冊。異步

注:上面程序實際上是有問題,本處只作mq_notify函數的使用示例。函數

 

2011-11-18  任洪彩  qdurenhongcai@163.com線程

轉載請註明出處。指針

相關文章
相關標籤/搜索