Linux下模拟一个简易的消息机制
消息机制是WIN32的核心,本质就是一个消息结构的链表。
声明
#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 longWPARAM; typedef unsigned longLPARAM; typedef unsigned intUINT; typedef intMSG_BOOL;//这个返回值很二 不要喷我... typedef struct
{
UINTmessage;//消息类型 UINTidThread;//线程ID WPARAMwParam;
LPARAMlParam;
}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;
}
测试用例只是做了一些简单基础的测试,并不完善。
除了线程相关的系统调用,全部采用标准库实现。