Message Queue C on Unix/Linux

2011-02-13 / C/C++, MAC, Programming, Server, Unix/Linux / 51 Comments

วันนี้อยู่บ้านวันอาทิตย์ว่าง ๆ ไม่ได้ทำอะไร ก็เลยมานั่งหาอะไรอ่าน เอาความรู้ใส่สมอง ซักหน่อย
ก็เลยมาอ่านเกี่ยวกับเรื่อง Message Queue และก็ลองเขียนเล่นๆ ดู ก็ผมจะสรุปตามความเข้าใจของผม และย่อตัวอย่าง Code ที่ใช้งานดูนะครับ

Message Q คืออะไร และใช้ทำอะไร ?

ก่อนที่จะมาทำความรู้จักกับ Message Queue เรามาทำความรู้จักกับ IPC กันก่อน IPC หรือ Interprocess Communication มีไว้เพื่อการติดต่อสื่อสาร จะใช้ในการติดต่อสื่อสารระหว่าง Thread ภายใน Process เดียวกันก็ได้ หรือ จะใช้ในการติดต่อสารระหว่าง Process ก็ได้
โดยการสื่อสารของ IPC มีหลายชนิด และแต่ละชนิดมีข้อดีข้อเสียแตกต่างกันไปครับ

  • Pipes
  • Signal
  • Message Queue
  • Shared Memory
  • Socket
  • Semaphores

Page จะพูดเรื่อง Message Queue ก่อนนะครับ แล้วผมจะค่อย ๆ เพิ่มในส่วนอื่นให้ภายหลัง Message Queue สามารถติดต่อสื่อสารกันภายใน OS เดียวกันได้เท่านั้น คือ ตัว Message Queue ไม่สามารถสื่อสารข้ามเครื่องได้ ต้องอยู่ภายใต้เครื่องเดียวกันเท่านั้น

โดยการทำงานคร่าวๆ ของ Message Queue นั้นแน่นอนว่าจะมีในส่วนของการส่งและการรับ และที่เพิ่มเข้ามาจะเป็นในส่วนของ Passing Module ซึ่งทำหน้าที่เป็นตัวกลางในการจัดการ รับ-ส่ง Message ให้กับทั้ง 2 Process และ ใน Process ทั้งสองจะต้องกำหนดค่า Key ขึ้น ให้ตรงกัน เช่น Process ที่ส่ง ส่งด้วย Key 1234 ใน Process ในการรับก็ต้องรับ ด้วย Key 1234 ด้วย

ในใช้งาน Function หรือ type ต่าง ๆ ของ Message Queue จะต้อง include header file 3 file ดังนี้

  • #include <sys/types.h>
  • #include <sys/ipc.h>
  • #include <sys/msg.h>

function หลักๆ ของ Message ที่ใช้มีดังนี้ msgget(), msgsnd(), msgrcv()

  • int msgget(key_t key, int msgflg)
  • int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
  • int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

1. msgget ใช้ในการสร้างช่องทางในการรับ-ส่ง

  • return ค่าของ Messsage Queue ID มาให้หาก function นี้ทำงานสำเร็จ และ return -1 หาก error
  • key คือเลขคือ ซื่งตัวแปล key จะมีขนาด เทียบเท่า unsigned long
  • msgflg คือ parameter ที่ใช้ตั้งค่า permission และ control flag ของ message queue

2. msgsnd ใช้ในการส่ง

  • return หาก function นี้ทำงานไม่สำเร็จจะ return -1
  • msqid คือ message queue id ที่ได้จากการ call function msgget
  • msgp คือ structure ของ message ที่ จะส่งออกไป
  • msgsz คือ ขนาดของ structure ของ message ที่จะส่งออก
  • msgflg คือ flag เพื่อบอกว่า call function นี้แล้วให้ทำอะไร ส่วนใหญ่ที่ผมใช้คือ IPC_NOWAIT

3.msgrcv ใช้ในการรับ

  • return หาก function นี้ทำงานสำเร็จจะ return ขนาดของ Message ที่รับเข้ามา แต่หากไม่สำเร็จจะ return -1
  • msqid คือ Qessage Queue id ที่ได้จากการ call function msgget
  • msgp คือ structure ของ message ที่ จะรับเข้ามา
  • msgsz คือ ขนาดของ structure ของ message ที่จะรับเข้ามา
  • msgtyp คือ จะรับ Message type อะไร
  • msgflg คือ flag เพื่อบอกว่า call function นี้แล้วให้ทำอะไร

Code Example

โดยตัวอย่างผมจะแบ่งออกเป็น 2 Process (2 โปรแกรม)

  1. โปรแกรมส่ง Send Process
  2. โปรแกรมรับ Receive Process

1.msgq_send.c

/*************************
*@author Ultra MCU
*@file-name msgq_send.c
*@date 2011 02 13
*compile apple-darwin10-gcc-4.2.1 on OSX 10.6.4
*@e-mail ultra_mcu[AT]msn>com
*@website http://www.im-ai.com
*************************/

#include
#include
#include
#include

#define _TRUE_ 0
#define _FALSE_ -1

typedef struct struct_message_text
{
long message_type;
char message_text[100];

}st_msg_txt;

int main (int argc, const char * argv[]) {

printf(“Hello, I’m send process.\r\n”);
send_process();
return 0;
}

int send_process()
{
st_msg_txt my_send_msg;
key_t msg_key;
int msg_flag;
int msg_q_id;
int msg_number;

msg_number = 0;
msg_key = 822; /* Message Queue Key 822 */
msg_flag = IPC_CREAT | 0666; /* IPC Create + Permission rw_rw_rw_ */
my_send_msg.message_type = 1; /* Message type 1 */
msg_q_id = msgget(msg_key, msg_flag);

if(msg_q_id > -1)
{
while(1)
{
sprintf(my_send_msg.message_text,”Message msg_number = %d”,msg_number);

if(msgsnd(msg_q_id, &my_send_msg, sizeof(st_msg_txt), IPC_NOWAIT) == _TRUE_)
{
printf(“SEND PROCESS : %s\r\n”,my_send_msg.message_text);
}
else
{
perror(“msgsnd”);
printf(“send message failed\r\n”);
return _FALSE_;
}

msg_number++;
sleep(1);
}
}
else
{
printf(“get message queue id failed\r\n”);
return _FALSE_;
}

return _TRUE_;

}

2.msgq_recv.c

/*************************
*@author Ultra MCU
*@file-name msgq_recv.c
*@date 2011 02 13
*compile apple-darwin10-gcc-4.2.1 on OSX 10.6.4
*@e-mail ultra_mcu[AT]msn>com
*@website http://www.im-ai.com
*************************/

#include
#include
#include
#include

#define _TRUE_ 0
#define _FALSE_ -1

typedef struct struct_message_text
{
long message_type;
char message_text[100];

}st_msg_txt;

int main (int argc, const char * argv[]) {

printf(“Hello, I’m recv process.\r\n”);
recv_process();
return 0;
}
int recv_process()
{
st_msg_txt my_recv_msg;
key_t msg_key;
int msg_flag;
int msg_q_id;
int recv_msg_type;

msg_key = 822; /* Message Queue Key 822 */
msg_flag = IPC_CREAT | 0666; /* IPC Create + Permission rw_rw_rw_ */
recv_msg_type = 1; /* Receive Message type 1 */

msg_q_id = msgget(msg_key, msg_flag);

if(msg_q_id > -1)
{
while(1)
{
if(msgrcv(msg_q_id, &my_recv_msg, sizeof(st_msg_txt),recv_msg_type , 0) < 0)
{
perror(“msgrcv”);
printf(“recv message failed\r\n”);
return _FALSE_;
}
else
{
printf(“RECV PROCESS : %s\r\n”,my_recv_msg.message_text);
}
}
}
else
{
printf(“get message queue id failed\r\n”);
return _FALSE_;
}

return _TRUE_;

}

ดังไฟล์ source code ตัวอย่างเป็นการรับส่ง message queue ด้วย key 822 และใช้ message type เป็น 1 โดย ทุกๆ 1 วินาที Process ที่ส่งจะส่งข้อความ “Message msg_number =XXX” ไปหา Process รับโดยเลข XXX จะนับเพิ่มขึ้นเรื่อย ๆ

Message Queue

จากตัวอย่าง หน้าจอสีแดงคือ Process รับ ส่วนหน้าจอสีขาวคือ Process ส่ง

นี่ก็เป็นตัวอย่างง่าย ๆ ของการสร้างการสื่อสารภายใน Application หรือระหว่าง Application ได้ง่ายและรวดเร็ว เพียงแค่เขียน code เพิ่มไม่กี่บรรทัด ซึ่งข้อดีของการใช้ Message Queue คือพัฒนาได้เร็ว รับส่งเร็ว แต่ข้อเสียคือขนาดของการส่งมีจำกัด ดูได้จากคำสั่ง ulimit -q แต่สามารถเปลี่ยนแปลงได้ ตามคำสั่งของ Unix นั้นๆ ครับ

ปล.หากต้องการนำไปเผยแพร่ ขอความกรุณาใส่เครดิต ให้ด้วยครับ ขอบคุณครับ

Ref : http://www.cs.cf.ac.uk/Dave/C/node25.html
Ref : http://linux.die.net/man/3/msgget

Read More

การใช้ semaphore lock function

2009-12-09 / C/C++, Computer, Programming / 7 Comments

วันนี้ทำงาน แล้วติดปัญหา ผมมี function นึงซึ่งใช้ในการจัดการ  Linked-List
ซึ่ง linked-list ตัวนี้ถูกประกาศเป็น global
และโปรแกรมที่ผมทำนั้น การทำงานถูกแยกเป็น thread
ดังนั้นโอกาสที่ จะมีการ access Linked-list ตัวนี้ก็มีสูง

ลูกพี่ผมก็แนะนำให้ใช้ semaphore lock โดยขณะที่ มี เธรดไหนทำอยู่ก็ให้ lock ไว้ก่อน
โดย syntax ที่ใช้มีดังนี้

#include <semaphore.h>    <—- Include

sem_t      mutex;   <— mutext variable

sem_wait(&mutex);   <—- Lock

sem_post(&mutex);  <—- Unlock

แต่ก่อนจะใช้ ต้อง Init ก่อนนะครับ

sem_init(&mutex, 0, 1);

เช่น

int editData()

{

sem_wait(&mutex);

A++;

sem_post(&mutex);

return A;

}

ข้อสำคัญคือ ต้อง Unlock ก่อนที่จะ Return นะครับ

ปล. ตอน compile ต้อง -lposix4 ด้วยนะครับ ^^

Read More