首页 > 代码库 > Linux下模拟一个简易的消息机制

Linux下模拟一个简易的消息机制

声明

#define MSG_ERROR 		-1
#define MSG_SUCCEED		0

#define MSG_TRUE		1
#define MSG_FALSE		0

#define PM_NOREMOVE   	0x00
#define PM_REMOVE   	0x01

typedef unsigned long 	WPARAM;
typedef unsigned long 	LPARAM;
typedef unsigned int	UINT;
typedef int				MSG_BOOL;//这个返回值很二 不要喷我...

typedef struct
{
	UINT 	message;//消息类型
	UINT 	idThread;//线程ID
	WPARAM	wParam;
	LPARAM	lParam;
}MSG;

typedef MSG* LPMSG;

typedef struct NODE
{
	MSG				data;
	struct NODE* 	next;
}MSG_NODE;

void SetupMessage();//启动消息队列

void TerminalMessage();//终止消息队列

MSG_BOOL PeekMessage(	LPMSG lpMsg,
						UINT hWnd,
						UINT wMsgFilterMin,
						UINT wMsgFilterMax,
						UINT wRemoveMsg);

MSG_BOOL PostThreadMessage(	UINT idThread,
							UINT msg, 
							WPARAM wParam, 
							LPARAM lParam);


实现

#include "msg.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <pthread.h>

static MSG_NODE * g_message_queue = NULL;

static MSG_NODE* msg_create()
{
	MSG_NODE* pHead = calloc(sizeof(MSG_NODE),1);
	return pHead;
}

static void msg_destroy(MSG_NODE* pHead)
{
	MSG_NODE* pNode = NULL;
	if(pHead)
	{
		pNode = pHead->next;
		while(pNode)
		{
			pHead->next = pNode->next;
			printf("Free Node:%p\n",pNode);
			free(pNode);
			pNode = pHead->next;
		}
		free(pHead);
		printf("Free Head Node:%p\n",pHead);
	}
}

//定位到消息列表尾部
static MSG_NODE* msg_tail(MSG_NODE* pHead)
{
	MSG_NODE* pTail = NULL;

	if(!pHead) return NULL;
	pTail = pHead;
	while(pTail->next) pTail = pTail->next;
	return pTail;
}

//尾部插入一个消息结点
static int msg_push_back(MSG_NODE* pHead, MSG_NODE* pNode)
{
	MSG_NODE* pTail = NULL;

	if( !pHead || !pNode) return MSG_ERROR;

	pTail = msg_tail(pHead);
	if(pTail)
	{
		pTail->next = pNode;
		pNode->next = NULL;
		return MSG_SUCCEED;
	}
	return MSG_ERROR;
}

//启动
void SetupMessage()
{
	if(!g_message_queue)
	{
		g_message_queue = msg_create();
		assert(g_message_queue);
	}
}

//终止
void TerminalMessage()
{
	msg_destroy(g_message_queue);
	g_message_queue = NULL;
}


MSG_BOOL PostThreadMessage(UINT idThread,UINT msg, WPARAM wParam, LPARAM lParam)
{
	MSG_NODE* pNode  = NULL;

	if( !g_message_queue && (msg < 0) ) return MSG_FALSE;

	pNode = calloc(sizeof(MSG_NODE),1);
	if (pNode)
	{
		pNode->data.message 	= msg;
		pNode->data.idThread 	= (!idThread)?pthread_self():idThread;//如果ID是0 默认为当前线程
		pNode->data.wParam 		= wParam;
		pNode->data.lParam 		= lParam;
		pNode->next 			= NULL;
		return (msg_push_back(g_message_queue,pNode) == MSG_SUCCEED)?MSG_TRUE:MSG_FALSE;
	}
	return MSG_FALSE;
}

//第二个参数完成为了函数"像" Win32 API 没有用处,LINUX没有窗口句柄这一说 
MSG_BOOL PeekMessage(LPMSG lpMsg,UINT HWND,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg)
{
	MSG_NODE*	pNode		= NULL;
	MSG_NODE*	pPreNode 	= NULL;//保存前一个结点

	if( !g_message_queue && lpMsg) return MSG_FALSE;

	pPreNode = g_message_queue;
	pNode = g_message_queue->next;
	
	/*
	*不要喷我 用这么多goto啊 只是为了 不要写一堆重复的代码
	*/
	while(pNode)
	{
		if(pNode->data.idThread != (UINT)pthread_self() )
		{
			goto NEXT;
		}

		if(wMsgFilterMin|wMsgFilterMax)
		{
			if( pNode->data.message >= wMsgFilterMin &&
				pNode->data.message <= wMsgFilterMax )
			{
				goto GET_MSG;
			}
		}
		else
		{
			goto GET_MSG;
		}

NEXT:
		pPreNode = pNode;
		pNode = pNode->next;
		continue;

GET_MSG:
		memcpy(lpMsg,&pNode->data,sizeof(MSG) );
		if(wRemoveMsg == PM_REMOVE)//删除消息链表结点
		{
			pPreNode->next = pNode->next;//前驱结点关联后继结点 防止链表截断
			free(pNode);//释放当前消息链表结点
		}
		return MSG_TRUE;
	}
	return MSG_TRUE;
}


测试用例

#include <stdio.h>
#include <string.h>
#include "msg.h"


int main(int argc,char** argv)
{
	int i=0;
	MSG msg;

	SetupMessage();

	for(i=0;i<10;i++)
	{
		PostThreadMessage(0,1000+i, 100+i, 200+i);
	}

	while(1)
	{
		PeekMessage(&msg,0,0,0,PM_REMOVE);
		printf("ID:%u,WPARAM:%lu,LPARAM:%lu\n",msg.message,msg.wParam,msg.lParam);
		if(!msg.message)break;
		memset(&msg,0,sizeof(MSG));
		sleep(2);
	}
	TerminalMessage();
	return 0;
}


测试用例只是做了一些简单基础的测试,并不完善。

除了线程相关的系统调用,全部采用标准库实现。