刘收获

导航

自定义消息队列

  参考周伟明前辈的《多任务下的数据结构与算法》实现的自定义的消息队列。 

 

0x01  消息队列机制

  消息队列是 一 种 可 以 有 多 个 任 务 同 时 问 队 列 里 发 送 和 接收 数 据 的 队 列 。 要 实 现 多个 任 务 同 时 向 队 列 里 收 发 数 据 , 那 么 必 须 在 收 发 操 作 上 加 上 俣 护 。 另 外 还 要 分 别 分析 队 列 为 空 和 队 列 为 满 的 情 况 。

  (1) . 队 列 为 空 的 情 况

  此 时 向 队 列 发 送 数 据 是 没 有 问题的 , 如 果 此 时 要 从 队 列 接 收 数 据 , 由 于 队 列 中 暂无 数 据 , 接 收 任 务 必 须 等 数 据 发 送 到 队 列 中 去 , 才 能 从 队 列 中 接 收 到 数 据

  (2), 队 列 为 满 的 情 况

  此 时 要 从 队 列 中 接 收 数 据 是 没 有 问题 的 , 如 吴 此 时 向 队 列 发 送 数 据 , 由 于 队列为满 , 发 送 任 务 必 须 等 待 其 他 任 务 从 队 列 里 将 数 据 接 收 出 去 , 才 能 将 数 据 发 送 到 队 列 中 。当 然 也 可 以 不 限 制 队 列 的 大 小 , 也 就 不 需 要 考 虑 队 列 满 的 情 况 了 , 不 过 要 保 证 发 送 到

队 列 里 的 数 据 数 量 的 上 界 值 不 会 超 过 系 统 的 负 荷 , 特 别 是 网 络 软 件 , 如 果 接 收 网 络 数据 放 人 消 息 队 列 中 , 而 不 设 置 队 列 大 小 限 就 很 容 易 受 到 攻 击 。

 

  消息队列实现框架: 

  (1).自定义构造消息,队列相关数据结构

  (2).一个线程负责依次从消息队列中取出消息,并处理该消息

  (3).多个线程产生事件,并将消息放进消息队列,等待处理

 

 

0x02  消息队列构造(代码)

   1.自定义消息队列结构体     

   (1)消 息 队 列 中 , 需 要 一 个 计 数 器 来 记 录 队 列 中 元 素 的 个 数 ,而且当计数为0时,要将接收 操 作 阻 塞 , 由 于 Semaphore 信 号 量 刚 好 有 这 个 特 性 ,因此可以使用信号量来实现计数功能。

           (2)使用双向链表构造队列

 typedef struct _MSG_QUEUE_{     
      PTASK_NODE TaskNode; /* 多任务链表 */       HANDLE SemaphoreHandleHandle; /* 处理队列为空情况的计数信号量*/       UINT MaxLength; /* 队列的最大长度 */ }MSG_QUEUE,*PMSG_QUEUE; typedef struct _TASK_NODE_ { PDOUBLE_LIST DoubleList; /* 双向链表指针 */ PEXIT_TASK ExitTask; /* 多任务退出结构指针 */ }TASK_NODE,*PTASK_NODE; typedef struct _EXIT_TASK_ { HANDLE MutexHandle; /* 操作锁 */ UINT ExitFlag; /* 退出标志 */ }EXIT_TASK,*PEXIT_TASK; typedef struct _DOUBLE_LIST_ { PDOUBLE_NODE HeadNode; /* 第1个节点的指针 */ PDOUBLE_NODE TailNode; /* 最后1个节点的指针 */ UINT NodeCount; /* 保存链表节点的个数 */ }DOUBLE_LIST, *PDOUBLE_LIST; typedef struct _DOUBLE_NODE_ { struct _DOUBLE_NODE_ *Flink; /* 下一个节点指针 */ struct _DOUBLE_NODE_ *Blink; /* 前一个节点指针 */ void *BufferData; /* 数据指针 */ }DOUBLE_NODE,*PDOUBLE_NODE;

  (2)发送消息,接受消息操作

     1>发送消息只需将数据加入到链表当中,计数加一。

       进行插入数据操作时,使用Mutex互斥体来实现多线程的安全性,具体插入数据操作:malloc新建一个节点,将数据插入到新节点的BufferData成员上,再将新节点的指向下一个节点的指针赋为空NULL,指向上一个节点的指针去指向尾节点(每次插入到消息队列的尾部),

           NewNode->Flink = NULL;    NewNode->Blink = DoubleList->TailNode;

       最后判断尾节点是否为空,如果为空表示原来链表中没有节点,此时的新节点既是头节点也是尾节点,应该将双向链表的头节点指针和尾节点指针都指向当前的新节点。

          DoubleList->HeadNode = NewNode;      DoubleList->TailNode = NewNode;

      如果不为空表示原来链表中有节点,则将尾节点下一节点指针指向新加入的 节点,并且尾节点指针也应该指向新节点 

          DoubleList->TailNode->Flink = NewNode;      DoubleList->TailNode = NewNode;

BOOL MsgQueue_Entern(PMSG_QUEUE MsgQueue, void* BufferData)
{
	BOOL  IsOk;

	IsOk = TaskList_Entern(MsgQueue->TaskNode, BufferData);   //由于是Queue所以采用 Tail插入


	//限制入队情况
	SeReleaseSemaphore(MsgQueue->SemaphoreHandleHandle, 1); /* 将计数加1 */

	return IsOk;
}
BOOL TaskList_Entern(PTASK_NODE TaskNode, void* BufferData)
{
	BOOL IsOk;

	SeWaitForSingleObject(TaskNode->ExitTask->MutexHandle);

	IsOk = DoubleList_Entern(TaskNode->DoubleList, BufferData);

	SeReleaseMutex(TaskNode->ExitTask->MutexHandle);

	return IsOk;
}
BOOL DoubleList_Entern(PDOUBLE_LIST DoubleList, void* BufferData)
{
	PDOUBLE_NODE NewNode = NULL;


    /* 参数校验 */
    if ( DoubleList == NULL || BufferData == NULL )
    {
        return FALSE;
    }

    /* 新建一个节点 */
    NewNode = (PDOUBLE_NODE)malloc( sizeof(DOUBLE_NODE));
    if ( NewNode == NULL )
    {
        return FALSE;
    }
 
	NewNode->BufferData = BufferData;  /* 将节点数据指针指向传进来的数据 */
    NewNode->Flink = NULL;             /* 将节点的下一节点赋为空指针NULL */
   
	
	NewNode->Blink = DoubleList->TailNode;      

    /*
     * 判断是否尾节点指针为空,如果为空表示原来链表中没有节点,
     * 此时应该将尾节点指向新加入的节点, 并且头节点指针也应该指向新节点 
     */
    if ( DoubleList->TailNode == NULL )
    {
        DoubleList->HeadNode = NewNode;
    }
    else
    {
        /*
         * 如果尾节点指针不为空,此时应该将尾节点下一节点指针指向新加入的 
         * 节点,并且尾节点指针也应该指向新节点 
         */
        DoubleList->TailNode->Flink = NewNode;
    }

    DoubleList->TailNode = NewNode;

    /* 将链表节点数据加1 */
    DoubleList->NodeCount++;
    
    return TRUE;
}

    2>接 收 消息 需 要 将 计 数 减 I, 并 且 当 计 数 为 0 时 要 阻 塞 接 收 操 作 ,直 到 有 数 据 到 来 才从队列(链表)中将数据取出来。

      删除节点前,先将信号量计数减1,信号计数为0则会阻塞住删除结点操作。

       然后将要弹出数据的节点指针指向链表头节点,弹出数据指针指向头节点的数据: 

          PopNode = DoubleList->HeadNode; BufferData = PopNode->BufferData;

      删除节点时,将头节点指针指向头节点的下一节点(第二个节点成为新的头节点),如果下一个节点存在的话(当前的新头节点不为空的话),将新头节点的Blink指针置为NULL。 

          DoubleList->HeadNode->Blink = NULL;

      最后链表节点数量减1,并判断链表的节点数量是否为0,如果链表的节点数量已经为0则表示原来只有一个节点,弹出头节点后,链表已经为空,没有节点在里面,此时应该将尾节点指针赋空  

          DoubleList->TailNode = NULL;

void* MsgQueue_Leave(PMSG_QUEUE MsgQueue)
{
	SeWaitForSingleObject(MsgQueue->SemaphoreHandleHandle); /* 将计数减1,计数为0则会阻塞住 */
	return TaskList_Leave(MsgQueue->TaskNode);

}

void * TaskList_Leave(PTASK_NODE TaskNode)
{
	void * BufferData;

	SeWaitForSingleObject(TaskNode->ExitTask->MutexHandle);

	BufferData = DoubleList_Leave(TaskNode->DoubleList);

	SeReleaseMutex(TaskNode->ExitTask->MutexHandle);

	return BufferData;
}
void* DoubleList_Leave(PDOUBLE_LIST DoubleList)
{
	PDOUBLE_NODE   PopNode;   /* 用来指向要弹出数据的节点的指针 */
	void*          BufferData;   /* 用来指向要弹出的数据的指针 */

    /* 参数校验 */
    if ( DoubleList == NULL || DoubleList->HeadNode == NULL ) 
    {
		return NULL;
    }

    /* 将要弹出数据的节点指针指向链表头节点,弹出数据指针指向头节点的数据 */
    PopNode = DoubleList->HeadNode;
    BufferData = PopNode->BufferData;

   

    /* 将头节点指针指向头节点的下一节点 */
    DoubleList->HeadNode = DoubleList->HeadNode->Flink;
    if ( DoubleList->HeadNode != NULL )
    {
        DoubleList->HeadNode->Blink = NULL;
    }
	
    /* 将链表节点数量减1 */
    DoubleList->NodeCount--;

    /* 如果链表的节点数量已经为0则表示原来只有一个节点,弹出头节点后,
     * 此时链表已经为空,没有节点在里面,此时应该将尾节点指针赋空
     * 当前节点指针由于前面已经处理过了,如果只有一个节点的话肯定为空
     * 所以这里不需要处理当前节点指针
     */
    if ( DoubleList->NodeCount == 0 ) {
		DoubleList->TailNode = NULL;
	}
	
    /* 释放弹出的节点, 注意这里并没有释放节点数据指针 */
    free( PopNode );

    return BufferData;    /* 返回头节点的数据指针 */
}

  

 

  3.消息队列的创造与释放

   1>消息队列的创造

    消 息 队 列 创 建 编  比 较 简 单 , 只 是 申 请 一 个 MSG_QUEUE 结 构 体 , 并 初 化 结 构体 成 员 , 然 后 返 创 建 时 , 信号量的 初 始 计 数 要 设 为 0 , 因 为 这 时 队 列 是 空。

 1 PMSG_QUEUE  MsgQueue_Create(INT MaxLength)
 2 {
 3     PMSG_QUEUE  MsgQueue = NULL;
 4 
 5     MsgQueue = (PMSG_QUEUE)malloc(sizeof(MSG_QUEUE));
 6     if (MsgQueue != NULL)
 7     {
 8         MsgQueue->SemaphoreHandleHandle = SeCreateSemaphore(0, MaxLength);
 9         if (MsgQueue->SemaphoreHandleHandle != NULL)
10         {
11             MsgQueue->MaxLength = MaxLength;
12             MsgQueue->TaskNode = TaskList_Create();
13             if (MsgQueue->TaskNode == NULL)
14             {
15                 SeCloseHandle(MsgQueue->SemaphoreHandleHandle);
16                 free(MsgQueue);
17                 MsgQueue = NULL;
18             }
19         }
20         else
21         {
22             free(MsgQueue);
23             MsgQueue = NULL;
24         }
25     }
26     return MsgQueue;
27 }
28 PTASK_NODE TaskList_Create(void)
29 {
30     PTASK_NODE  TaskNode = NULL;
31     TaskNode = (PTASK_NODE)malloc(sizeof(TASK_NODE));
32     if (TaskNode != NULL)
33     {
34         TaskNode->DoubleList = DoubleList_Create();
35         if (TaskNode->DoubleList != NULL)
36         {
37             TaskNode->ExitTask = ExitTask_Create();
38             if (TaskNode->ExitTask == NULL)
39             {
40                 free(TaskNode->DoubleList);
41                 free(TaskNode);
42                 TaskNode = NULL;
43             }
44         }
45         else
46         {
47             free(TaskNode);
48             TaskNode = NULL;
49         }
50     }
51     return TaskNode;
52 }
53 PDOUBLE_LIST DoubleList_Create(void)
54 {
55     PDOUBLE_LIST DoubleList = NULL;
56 
57     /* 分配内存操作 */
58     DoubleList = (PDOUBLE_LIST )malloc(sizeof(DOUBLE_LIST));
59     if (DoubleList != NULL)
60     {
61         /* 初始化链表结构体各指针成员为空,链表节点个数为0 */
62         DoubleList->HeadNode = NULL;
63         DoubleList->TailNode = NULL;
64         DoubleList->NodeCount = 0;
65     }
66 
67     return DoubleList;
68 }
69 PEXIT_TASK   ExitTask_Create()
70 {
71     PEXIT_TASK  ExitTask = NULL;
72 
73     ExitTask = (PEXIT_TASK)malloc(sizeof(EXIT_TASK));
74 
75     if (ExitTask != NULL)
76     {
77         ExitTask->MutexHandle = SeCreateMutex();
78         if (ExitTask->MutexHandle == NULL)
79         {
80             free(ExitTask);
81             return NULL;
82         }
83     
84         ExitTask->ExitFlag = TASK_NO_EXIT;
85     }
86     return ExitTask;
87 }
View Code

    

     2>消息队列的释放

    消 息 队列 的 释 放 操 作 要 比 创 建 操 作 复 杂 一 点 , 主 要 是 要 考 虑 退 出 的 资 源 释 放 问 题 。释 放 整 个 消 息 队 列 前 , 需 要 通 知 所 有 阻 塞 在 消 息 队 列 接 收 操 作 上 的 任 务 退 出 , 因 此 要使 用 ReleaseSemaphore将 计 数 值 设 最 大 。

 1 void MsgQueue_Destroy(PMSG_QUEUE MsgQueue, LPFN_DESTROYFUNCTION DestroyFunction)
 2 {
 3     if (MsgQueue != NULL)
 4     {
 5         INT MaxLength = 0;;
 6         if (MsgQueue->MaxLength > DEFAULT_MSGQUEUE_LENGTH)
 7         {
 8             MaxLength = MsgQueue->MaxLength;
 9         }
10         else
11         {
12             MaxLength = DEFAULT_MSGQUEUE_LENGTH;
13         }
14         SeReleaseSemaphore(MsgQueue->SemaphoreHandleHandle, MaxLength); /* 让所有阻塞的接收操作可以继续*/
15     
16         TaskList_Destroy(MsgQueue->TaskNode, DestroyFunction);
17         SeCloseHandle(MsgQueue->SemaphoreHandleHandle);
18         free(MsgQueue);
19     }
20 }
21 void TaskList_Destroy(PTASK_NODE TaskNode, LPFN_DESTROYFUNCTION DestroyFunction)
22 {
23 
24     if (TaskNode == NULL)
25     {
26         return;
27     }
28 
29     ExitTask_Destroy(TaskNode->ExitTask);
30 
31     DoubleList_Destroy(TaskNode->DoubleList, DestroyFunction);
32 
33     free(TaskNode);
34 
35 }
36 void DoubleList_Destroy(PDOUBLE_LIST DoubleList, LPFN_DESTROYFUNCTION DestroyFunction)
37 {
38     PDOUBLE_NODE TravleNode = NULL;
39 
40     if (DoubleList)
41     {
42         /* 从头节点开始,一个接一个释放链表节点及节点数据 */
43         TravleNode = DoubleList->HeadNode;
44         while (TravleNode != NULL)
45         {
46             PDOUBLE_NODE DeleteNode = NULL;
47 
48             DeleteNode = TravleNode;
49             TravleNode = TravleNode->Flink;
50 
51             if (DestroyFunction != NULL && DeleteNode->BufferData != NULL)
52             {
53                 /* 释放数据 */
54                 (*DestroyFunction)(DeleteNode->BufferData);
55             }
56             free(DeleteNode); /* 释放节点 */
57         }
58         /* 释放链表结构体 */
59         free(DoubleList);
60     }
61 }
62 void ExitTask_Destroy(PEXIT_TASK ExitTask)
63 {
64     SeWaitForSingleObject(ExitTask->MutexHandle);
65 
66     ExitTask->ExitFlag = TASK_EXIT;
67 
68 
69     
70     SeReleaseMutex(ExitTask->MutexHandle);
71 
72     /* 关闭操作的锁和退出事件 */
73     SeCloseHandle(ExitTask->MutexHandle);
74 
75     free(ExitTask);
76 }
View Code

 

 

 

posted on 2017-08-22 15:59  沉疴  阅读(557)  评论(0编辑  收藏  举报