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;

}

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

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

相关推荐