Linux POSIX Message Queue使用体験

3714 ワード

最近LinuxでPOSIX Message Queue(以下MQと略称する)を使ってプロセス間通信をしていますが、現在の私のシステムのリリース版とコンパイラにとって、MQは少し体得しています.チュートリアルでは説明されていません.あるいは、私がよく見ていないので、発見しませんでした.
参考資料
《The Linux Programming Interface - A Linux and UNIX System Programming Handbook》2010
テストシステム:
Linux Mint 3.11.0-12-generic x86_64 GNU/Linux, MPICH2, mpic++ (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
先着コード
// UNIX IPC functionalities
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
// POSIX Message Queue
#include 

// C++ header files
#include 
#include 
#include 


int receiveMsg(mqd_t *mqdes)
{
	unsigned int prio;   // priority of the message
	struct mq_attr attr; // attribute
	ssize_t numRead;     // size of message

	if (mqdes == NULL)
	{
		std::cout << "mqdes == NULL" << std::endl;
		exit(EXIT_FAILURE);
	}

	do
	{
		sleep(1);

		std::cout << "Check for new message." << std::endl;

		if (mq_getattr(*mqdes, &attr) == -1)
		{
			// this is an error
			std::cout << "In receiveMsg(), get attribute error." << std::endl;
			exit(EXIT_FAILURE);
		}
	}while (attr.mq_curmsgs == 0);

	// allocate memory for the incoming messages
	char * buffer = (char *)malloc(attr.mq_msgsize);
	if (buffer == NULL)
	{
		std::cout << "In receiveMsg(), malloc error." << std::endl;
		exit(EXIT_FAILURE);
	}
	memset(buffer,0,attr.mq_msgsize);
	// test use
//	memset(buffer,1,attr.mq_msgsize);

	for (int i=0;i

あまり話さないで、体得:
===============================================================
Messageは実はbyteカウントのメモリデータで、文字列ではありません!
================================================================
Messageという名前は広く付けられており、マニュアルを見ると、例を挙げると文字列も転送されています.そこで自分で実現した場合,当然ながらMQはリアルタイムで伝送される文字列であると考えたが,これは間違っていた.
今日実際にデバッグしたときにこの問題が発生しました.具体的な表現形式はmqです.receive()関数呼び出し後、bufferには正常な文字列の末尾に奇妙な文字がたくさんあります.最初は文字コードかどうかの問題を感じていたが、OSで調べてみると似ていないような気がして、bufferを初期化していないことに気づいた.
初期化されていないメモリを使用するのはタブーですが、デバッグ中にサボってしまったのは、送信されたMessageが文字列であることを無意識に考えていたため、必ずエンド'0'の文字がbufferに自動的に追加されることを意味しています.実はそうではありません.『マニュアル』の例でも、送信されたMessageの長さは文字列のstrlen()の結果であり、つまり最後の'0'は含まれていないことが明らかになっています.送信時に1文字列のヘッダアドレスを送信対象コンテンツの先頭とするが、最終送信の長さはstrlen()のみであり、実際の文字列よりメモリ消費量が1 byte少ない.mq_receive()の場合、MQは最後の'0'を自動的に追加しません.この必要がないからです.Messageは文字列ではありません.
だからmq_を振り返るreceive()関数の宣言は,はっと悟った.
ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio);

戻り値とは、Messageが文字列ではないため、現在受信されているmessageのbyte数を指します.
MQのMessageは実際にbyteでカウントされたメモリであり、MQはこのメモリをkernelにメッセージとして送信し、他のプロセスはkernelからこのメモリのデータを取得(コピー)する.
実際、文字列を送信したい場合は、2つの方法があります.送信時に1バイト多く送信するか、受信前にbufferを初期化し、必ず0に初期化しなければなりません.そうしないと、今日以前に発生した問題が発生します.尻尾に奇妙な文字が山積みになります(receiveMsg()のmemset()でこのbugをデバッグできます).
P.S.:Messageを送信するにはpython 2.7コードを使用します.ここから取得します.インストールする前にpython 2.7-devをインストールする必要があります.
https://pypi.python.org/pypi/posix_ipc