unix线程消息队列

分这么三步吧:
一:创建消息队列
二:向消息队列发送消息
三:从消息队列接收消息
用到的几个主要函数:
1、消息创建函数:
  msgget(key_t key,int msgflg);
  函数说明:
    返回值:如果成功,返回消息队列标识符
  如果失败,则返回-1:errno=EACCESS(权限不允许)
  EEXIST(队列已经存在,无法创建)
  EIDRM(队列标志为删除)
  ENOENT(队列不存在)
  ENOMEM(创建队列时内存不够)
  ENOSPC(超出最大队列限制)
    系统调用msgget()中的第一个参数是关键字值(通常是由ftok()返回的)。然后此关键字值将会和其他已经
  存在于系统内核中的关键字值比较。这时,打开和存取操作是和参数msgflg中的内容相关的。 IPC_CREAT如果
  内核中没有此队列,则创建它。 IPC_EXCL当和IPC_CREAT一起使用时,如果队列已经存在,则失败。
    如果单独使用IPC_CREAT,则msgget()要么返回一个新创建的消息队列的标识符,要么返回具有相同关键字
  值的队列的标识符。如果IPC_EXCL和IPC_CREAT一起使用,则msgget()要么创建一个新的消息队列,要么如果
  队列已经存在则返回一个失败值-1。IPC_EXCL单独使用是没有用处的。
2、消息发送函数:
  int msgsnd ( int msqid, struct msgbuf *msgp, int msgsz, int msgflg );
  函数说明:
  返回值: 
    0 :on success
    -1 :on error: errno = EAGAIN (queue is full, and IPC_NOWAIT was asserted)
    EACCES (permission denied, no write permission)
    EFAULT (msgp address isn't accessable – invalid)
    EIDRM (The message queue has been removed)
    EINTR (Received a signal while waiting to write)
    EINVAL (Invalid message queue identifier, nonpositive message type, or invalid message size)
    ENOMEM (Not enough memory to copy message buffer)
    传给msgsnd()函数的第一个参数msqid 是消息队列对象的标识符(由msgget()函数得到),第二个参数
    msgp 指向要发送的消息所在的内存,第三个参数msgsz 是要发送信息的长度(字节数),可以用以下的公
    式计算:
    msgsz = sizeof(struct mymsgbuf) - sizeof(long);
    第四个参数是控制函数行为的标志,可以取以下的值:
      0,忽略标志位;
      IPC_NOWAIT,如果消息队列已满,消息将不被写入队列,控制权返回调用函数的线程。如果不指定这个参
数,线程将被阻塞直到消息被可以被写入。
3、消息接收函数:
   int msgrcv ( int msqid, struct msgbuf *msgp, int msgsz, long mtype, int msgflg );
   函数说明:
   返回值:接收缓冲区中接收到得消息字节数。
   -1 on error: errno = E2BIG (Message length is greater than msgsz,no MSG_NOERROR)
   EACCES (No read permission)
   EFAULT (Address pointed to by msgp is invalid)
   EIDRM (Queue was removed during retrieval)
   EINTR (Interrupted by arriving signal)
   EINVAL (msgqid invalid, or msgsz less than 0)
   ENOMSG (IPC_NOWAIT asserted, and no message exists in the queue to satisfy the request)
   函数的前三个参数和msgsnd()函数中对应的参数的含义是相同的。第四个参数mtype
   指定了函数从队列中所取的消息的类型。函数将从队列中搜索类型与之匹配的消息并将之
   返回。不过这里有一个例外。如果mtype 的值是零的话,函数将不做类型检查而自动返回
   队列中的最旧的消息。
   第五个参数依然是是控制函数行为的标志,取值可以是:
   0,表示忽略;
   IPC_NOWAIT,如果消息队列为空,则返回一个ENOMSG,并将控制权交回调用函数
   的进程。如果不指定这个参数,那么进程将被阻塞直到函数可以从队列中得到符合条件的
消息为止。如果一个client 正在等待消息的时候队列被删除,EIDRM 就会被返回。如果进
程在阻塞等待过程中收到了系统的中断信号,EINTR 就会被返回。
MSG_NOERROR,如果函数取得的消息长度大于msgsz,将只返回msgsz 长度的信息,
剩下的部分被丢弃了。如果不指定这个参数,E2BIG 将被返回,而消息则留在队列中不被
取出。
当消息从队列内取出后,相应的消息就从队列中删除了。
 
 
ipc_msg_queue.c
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/msg.h>
#include <unistd.h>
#include <string.h>
#include "ipc_msg_queue.h"
static int g_msg_queue_id = 0;
static pthread_t g_msg_rcv_threadTid;
static pthread_t g_msg_snd_threadTid;
static void *msg_send_thread(void *arg)
{
	trap_message msg;
	int type = 0;

	memset(&msg, 0, sizeof(msg));
	printf("send thread enter......\n");

	while( 1 )
	{
		type = random()%5+1;
		switch(type)
		{
			case 1:
				strcpy(msg.msg_text, "AAAAAAAAAA");
				break;
			case 2:
				strcpy(msg.msg_text, "BBBBBBBBBB");
				break;
			case 3:
				strcpy(msg.msg_text, "CCCCCCCCCC");
				break;
			case 4:
				strcpy(msg.msg_text, "DDDDDDDDDD");
				break;
			case 5:
				strcpy(msg.msg_text, "FFFFFFFFFF");
				break;
			default:
				strcpy(msg.msg_text, "*******");
				break;
		}
		msg.msg_type = type;
		printf("msg type: %d\n", type);

		if( (msgsnd(g_msg_queue_id, &msg, sizeof(msg), IPC_NOWAIT)) != 0)
		{
			printf("send msg error!\n");
		}
		else
		{
			printf("send msg: %s succeed!\n", msg.msg_text);
		}
		sleep(1);
	}

}
static void *msg_rcv_thread(void *arg)
{
	trap_message msg = {0};
	int msg_len = 0;
	printf("manage thread enter......\n");

	while( 1 )
	{
		memset(&msg, 0, sizeof(msg));

		msg_len = msgrcv(g_msg_queue_id, &msg, sizeof(msg.msg_text), 0, IPC_NOWAIT);
		if(msg_len < 0)
		{
			sleep(3);
			continue;
		}
		sleep(2);
		printf("recv msg: %s\n", msg.msg_text);

	}

}
int main()
{
	int fd = -1;
	key_t key;

	fd = open("/home/zmc/test/c_code/msg_queue",  O_CREAT, 0660);
	if ( -1 == fd )
	{
		printf("Open msg_queue file error!\n");
		return -1;
	}
	close(fd);

	key = ftok("/home/zmc/test/c_code/msg_queue", 't');
	if(key == -1) {
		printf("init_module ftok error\n");
		return -1 ;
	}
	if((g_msg_queue_id  =  msgget(key, IPC_CREAT|0666)) == -1 )
	{
		printf ("msgget failed !\n");
		return  -1;
	}

	printf("create msg queue succeed......\n");
	//创建消息发送线程
	if(pthread_create(&g_msg_snd_threadTid, NULL, msg_send_thread, NULL)  != 0)
	{
		printf("Create msg send manage Thread failed\n");
		return -1;
	}

	//创建消息处理线程
	if(pthread_create(&g_msg_rcv_threadTid, NULL, msg_rcv_thread, NULL)  != 0)
	{
		printf("Create msg rcv Thread failed\n");
		return -1;
	}

	while ( 1 )
	{
		sleep(1);
	}

	return 0;
}
ipc_msg_queue.h
#ifndef PLC_TRAP_H
#define   PLC_TRAP_H
typedef struct _trap_message
{
	long msg_type;  //存储消息类型                    
	unsigned char msg_text[128];   //存储消息内容
}trap_message;
#endif PLC_TRAP_H


结果:

send msg: DDDDDDDDDD succeed!
msg type: 2
send msg: BBBBBBBBBB succeed!
recv msg: FFFFFFFFFF
msg type: 3
send msg: CCCCCCCCCC succeed!
msg type: 1
send msg: AAAAAAAAAA succeed!
recv msg: CCCCCCCCCC
msg type: 4
send msg: DDDDDDDDDD succeed!
msg type: 1
send msg: AAAAAAAAAA succeed!
recv msg: AAAAAAAAAA
msg type: 2
send msg: BBBBBBBBBB succeed!
msg type: 3
send msg: CCCCCCCCCC succeed!








   

你可能感兴趣的:(linux快速管理与开发)