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
先着コード
あまり話さないで、体得:
===============================================================
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()関数の宣言は,はっと悟った.
戻り値とは、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
参考資料
《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