C 言語から簡単に使える MQ がないかと思って調べてみたら、POSIX Message Queue が恐ろしく便利だったのでメモ。
動作については Java のBlockingQueueをプロセスを跨いで使えるようなイメージです。
† サンプルプログラム
今回のプログラムは送信側qsend と受信側qrecv の2つに分かれています。
qsend は 0, 1, 2・・・ というように文字表示しながら、その文字を /testq という Queue に書き込み続けるプログラムになっています。
対になるqrecv は /testq という Queue から文字を取り出して表示を行います。
今回は Queue のサイズを 10 に設定しているので、溜まっているメッセージの数が 10 個になると qsend は mq_send() 部分でブロックし、Queue が空くのを待ちます。qrecv は溜まっているメッセージの数が 0 個になると、mq_receive() 部分でブロックし、新しいメッセージの到着を待ちます。
一見、機能はパイプと大差ない感じに見えるかもしれませんが、このプログラムはどちらから起動しても大丈夫です。
また、qsend, qrecv 共に複数個起動しても問題なく動作します。
qsend.c
#include <mqueue.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <errno.h>#define QNAME "/testq"int main(){int cnt = 0;int ret;char str[100];char *buff;mqd_t q;struct mq_attr attr;attr.mq_flags = 0;attr.mq_maxmsg = 10;attr.mq_msgsize = 1024;attr.mq_curmsgs = 0;mode_t omask;omask = umask(0);q = mq_open(QNAME, (O_WRONLY | O_CREAT), 0777, &attr);umask(omask);if ( q == -1 ){printf("[ERROR]%d: %s\n", errno, strerror(errno));return 1;}while(1){sprintf(str ,"%d", cnt++);buff = (char *)calloc(strlen(str) + 1, sizeof(char));strcpy( buff, str );printf("%s\n", buff);ret = mq_send( q, buff , strlen(buff) , 0);if ( ret == -1) {printf("[ERROR]%d: %s\n", errno, strerror(errno));return 1;}free(buff);sleep(1);}}
qrecv.c
#include <mqueue.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <errno.h>#define QNAME "/testq"int main(){mqd_t q;struct mq_attr attr;char *buff;ssize_t n;int i;q = mq_open(QNAME, O_RDONLY);if ( q == -1 ){printf("[ERROR]%d: %s\n", errno, strerror(errno));return 1;}while(1){mq_getattr( q ,&attr );buff = (char *)malloc(attr.mq_msgsize);n = mq_receive( q, buff, attr.mq_msgsize, NULL);if ( n == -1) {printf("[ERROR]%d: %s\n", errno, strerror(errno));return 1;}for (i = 0; i < n; i++) putchar(buff[i]);putchar('\n');fflush(stdout);free(buff);}}
† コンパイルと実行
以下のオプションでコンパイルし、./qsend と ./qrecv を好きなだけ起動すれば動作がわかります。
gcc qrecv.c -lrt -o qrecvgcc qsend.c -lrt -o qsend
† 参考