Linux学习之"实现Windows消息机制"
一.为了适应需要,修改了"CLEvent":
头文件:
#ifndef CLEVENT_H
#define CLEVENT_H
#include "CLStatus.h"
#include "CLMutex.h"
#include "CLConditionVariable.h"
class CLEvent
{
public:
/*
构造函数和析构函数出错时,会抛出字符串类型异常
*/
CLEvent( );
explicit CLEvent(bool bSemaphore);
virtual ~CLEvent();
public:
CLStatus Set();
CLStatus Wait();
private:
CLEvent(const CLEvent&);
CLEvent& operator=(const CLEvent&);
private:
CLMutex m_Mutex;
CLConditionVariable m_Cond;
volatile int m_Flag;
bool m_bSemaphore;
};
#endif
实现:
#include "CLEvent.h"
#include "CLCriticalSection.h"
#include "CLLog.h"
CLEvent::CLEvent()
{
m_Flag = 0;
m_bSemaphore = false;
}
CLEvent::CLEvent(bool bSemaphore)
{
m_Flag = 0;
m_bSemaphore = bSemaphore;
}
CLEvent::~CLEvent()
{
}
CLStatus CLEvent::Set()
{
try
{
CLCriticalSection cs(&m_Mutex);
m_Flag++;
}
catch(const char *str)
{
CLLog::WriteLogMsg("In CLEvent::Set(), exception arise", 0);
return CLStatus(-1, 0);
}
CLStatus s = m_Cond.Wakeup();
if(!s.IsSuccess())
{
CLLog::WriteLogMsg("In CLEvent::Set(), m_Cond.Wakeup error", 0);
return CLStatus(-1, 0);
}
return CLStatus(0, 0);
}
CLStatus CLEvent::Wait()
{
try
{
CLCriticalSection cs(&m_Mutex);
while(m_Flag == 0)
{
CLStatus s = m_Cond.Wait(&m_Mutex);
if(!s.IsSuccess())
{
CLLog::WriteLogMsg("In CLEvent::Wait(), m_Cond.Wait error", 0);
return CLStatus(-1, 0);
}
}
if(m_bSemaphore)
{
m_Flag--;
}
else
{
m_Flag = 0;
}
}
catch(const char* str)
{
CLLog::WriteLogMsg("In CLEvent::Wait(), exception arise", 0);
return CLStatus(-1, 0);
}
return CLStatus(0, 0);
}
增加了一个bool变量m_bSemaphore,考虑如下情况:
在若干个线程调用Wait()被挂起前,Set()被执行了多次(一个线程或多个线程),也就是说此时m_Flag>1;当没有设置m_bSemaphore的时候,此时,一个等待的线程被唤醒后,又将m_Flag置为0,所以其他线程又被挂起;简而言之,这种情况下的m_Flag不具备记忆性,不管之前发了多少唤醒信号,都只能唤醒一个线程。
当m_bSemaphore=true时,m_Flag具备记忆性,之前发了多少信号,就能唤醒多少个线程。这是符合“生产者、消费者模型”的应用,也是消息机制所期望的(不希望发了多个消息,却只有一个消息被响应)。
二.封装了消息队列类(基于STL的queue)
头文件:
#ifndef CLMessageQueue_H
#define CLMessageQueue_H
#include <queue>
#include "CLStatus.h"
#include "CLMutex.h"
#include "CLEvent.h"
class CLMessage;
/*
该类是线程安全的
若要和CLMsgLoopManagerForMsgQueue 结合使用,则该类对象需要从堆中分配,且不用调用delete
*/
class CLMessageQueue
{
public:
/*
构造函数和析构函数出错时,会抛出字符串类型的异常
*/
CLMessageQueue();
virtual ~CLMessageQueue();
public:
CLStatus PushMessage(CLMessage * pMessage);
CLMessage* GetMessage();
private:
CLStatus Push(CLMessage * pMessage);
CLMessage* Pop();
private:
CLMessageQueue(const CLMessageQueue&);
CLMessageQueue& operator=(const CLMessageQueue&);
private:
std::queue<CLMessage*> m_MessageQueue;
CLMutex m_Mutex;
CLEvent m_Event;
};
#endif
实现:
#include "CLMessageQueue.h"
#include "CLCriticalSection.h"
#include "CLMessage.h"
#include "CLLog.h"
CLMessageQueue::CLMessageQueue() : m_Event(true)
{
}
CLMessageQueue::~CLMessageQueue()
{
while(true)
{
CLMessage *pMsg = Pop();
if(pMsg == 0)
break;
delete pMsg;
}
}
CLStatus CLMessageQueue::PushMessage(CLMessage * pMessage)
{
CLStatus s = Push(pMessage);
if(!s.IsSuccess())
{
CLLog::WriteLogMsg("In CLMessageQueue::PushMessage(), Push error", 0);
return CLStatus(-1, 0);
}
CLStatus s2 = m_Event.Set();
if(!s2.IsSuccess())
{
CLLog::WriteLogMsg("In CLMessageQueue::PushMessage(), m_Event.Set error", 0);
return CLStatus(-1, 0);
}
return CLStatus(0, 0);
}
CLMessage* CLMessageQueue::GetMessage()
{
CLStatus s = m_Event.Wait();
if(!s.IsSuccess())
{
CLLog::WriteLogMsg("In CLMessageQueue::GetMessage(), m_Event.Wait error", 0);
return 0;
}
return Pop();
}
CLStatus CLMessageQueue::Push(CLMessage * pMessage)
{
try
{
CLCriticalSection cs(&m_Mutex);
m_MessageQueue.push(pMessage);
}
catch(const char* str)
{
CLLog::WriteLogMsg("In CLMessageQueue::Push(), exception arise", 0);
delete pMessage;
return CLStatus(-1, 0);
}
return CLStatus(0, 0);
}
CLMessage* CLMessageQueue::Pop()
{
try
{
CLCriticalSection cs(&m_Mutex);
if(m_MessageQueue.empty())
return 0;
CLMessage *p = m_MessageQueue.front();
m_MessageQueue.pop();
return p;
}
catch(const char* str)
{
CLLog::WriteLogMsg("In CLMessageQueue::Pop(), exception arise", 0);
return 0;
}
}
这个队列是可增长的,理论上没有上限。同步了进队和出队操作,即有消息才能GetMessage(),否则阻塞。
问题,能否用其它手段实现队列?
三.消息循环的封装
1.消息处理函数类(回调函数类)"CLMessageObserver",其作用相当于FunctionProvider
头文件:
#ifndef CLMESSAGEOBSERVER_H
#define CLMESSAGEOBSERVER_H
#include "CLStatus.h"
class CLMessageLoopManager;
class CLMessageObserver
{
public:
CLMessageObserver();
virtual ~CLMessageObserver();
/*
需要在初始化中,完成消息处理函数的注册
*/
virtual CLStatus Initialize(CLMessageLoopManager *pMessageLoop, void* pContext) = 0;
private:
CLMessageObserver(const CLMessageObserver&);
CLMessageObserver& operator=(const CLMessageObserver&);
};
#endif
实现:
#include "CLMessageObserver.h"
CLMessageObserver::CLMessageObserver()
{
}
CLMessageObserver::~CLMessageObserver()
{
}
这个类的主要作用是把具体的消息处理函数同消息队列的实现(队列?管道?)分离开来。
在Initialize中传入CLMessageLoopManager参数可以使消息直接发送到处理函数,而避免使用"开关结构"。
与队列实现无关的消息循环管理器类"CLMessageLoopManager"(抽象类)
头文件:
#ifndef CLMessageLoopManager_H
#define CLMessageLoopManager_H
#include <map>
#include "CLStatus.h"
class CLMessageObserver;
class CLMessage;
class CLExecutiveInitialFinishedNotifier;
typedef CLStatus (CLMessageObserver::*CallBackForMessageLoop)(CLMessage *);
#define QUIT_MESSAGE_LOOP 1
struct SLExecutiveInitialParameter
{
void *pContext;
CLExecutiveInitialFinishedNotifier *pNotifier;
};
/*
该继承体系对象应从堆中分配,不必显示调用delete
若消息处理函数在CLStatus的返回对象中,若返回QUIT_MESSAGE_LOOP返回值,将导致退出消息循环
*/
class CLMessageLoopManager
{
public:
/*
pMessageObserver应从堆中分配,且不用调用delete
*/
CLMessageLoopManager(CLMessageObserver *pMessageObserver);
virtual ~CLMessageLoopManager();
virtual CLStatus EnterMessageLoop(void *pContext);
public:
/*
MessageObserver调用此函数,用于注册具体的消息处理函数
*/
virtual CLStatus Register(unsigned long lMsgID, CallBackForMessageLoop pMsgProcessFunction);
protected:
/*
初始化与反初始化消息循环,需要保证消息队列已经建立完毕
*/
virtual CLStatus Initialize() = 0;
virtual CLStatus Uninitialize() = 0;
virtual CLMessage* WaitForMessage() = 0;
virtual CLStatus MessageDispatch(CLMessage *pMessage);
private:
CLMessageLoopManager(const CLMessageLoopManager&);
CLMessageLoopManager& operator=(const CLMessageLoopManager&);
protected:
CLMessageObserver *m_pMessageObserver;
std::map<unsigned long, CallBackForMessageLoop> m_MsgMappingTable;
};
#endif
实现:
#include "CLMessageLoopManager.h"
#include "CLMessageObserver.h"
#include "CLMessage.h"
#include "CLLog.h"
#include "CLExecutiveInitialFinishedNotifier.h"
CLMessageLoopManager::CLMessageLoopManager(CLMessageObserver *pMessageObserver)
{
m_pMessageObserver = pMessageObserver;
}
CLMessageLoopManager::~CLMessageLoopManager()
{
if(m_pMessageObserver != 0)
delete m_pMessageObserver;
}
CLStatus CLMessageLoopManager::Register(unsigned long lMsgID, CallBackForMessageLoop pMsgProcessFunction)
{
m_MsgMappingTable[lMsgID] = pMsgProcessFunction;
return CLStatus(0, 0);
}
CLStatus CLMessageLoopManager::EnterMessageLoop(void *pContext)
{
SLExecutiveInitialParameter *para = (SLExecutiveInitialParameter *)pContext;
if(m_pMessageObserver == 0)
{
CLLog::WriteLogMsg("In CLMessageLoopManager::EnterMessageLoop(), m_pMessageObserver == 0", 0);
para->pNotifier->NotifyInitialFinished(false);
return CLStatus(-1, 0);
}
CLStatus s = Initialize();
if(!s.IsSuccess())
{
CLLog::WriteLogMsg("In CLMessageLoopManager::EnterMessageLoop(), Initialize error", 0);
para->pNotifier->NotifyInitialFinished(false);
return CLStatus(-1, 0);
}
CLStatus s1 = m_pMessageObserver->Initialize(this, para->pContext);
if(!s1.IsSuccess())
{
CLLog::WriteLogMsg("In CLMessageLoopManager::EnterMessageLoop(), m_pMessageObserver->Initialize error", 0);
CLStatus s2 = Uninitialize();
if(!s2.IsSuccess())
CLLog::WriteLogMsg("In CLMessageLoopManager::EnterMessageLoop(), Uninitialize() error", 0);
para->pNotifier->NotifyInitialFinished(false);
return CLStatus(-1, 0);
}
para->pNotifier->NotifyInitialFinished(true);
while(true)
{
CLMessage *pMsg = WaitForMessage();
if(pMsg == 0)
{
CLLog::WriteLogMsg("In CLMessageLoopManager::EnterMessageLoop(), pMsg == 0", 0);
continue;
}
CLStatus s3 = MessageDispatch(pMsg);
delete pMsg;
if(s3.m_clReturnCode == QUIT_MESSAGE_LOOP)
break;
}
CLStatus s4 = Uninitialize();
if(!s4.IsSuccess())
{
CLLog::WriteLogMsg("In CLMessageLoopManager::EnterMessageLoop(), Uninitialize() error", 0);
return CLStatus(-1, 0);
}
return CLStatus(0, 0);
}
CLStatus CLMessageLoopManager::MessageDispatch(CLMessage *pMessage)
{
std::map<unsigned long, CallBackForMessageLoop>::iterator it;
it = m_MsgMappingTable.find(pMessage->m_clMsgID);
if(it == m_MsgMappingTable.end())
{
CLLog::WriteLogMsg("In CLMessageLoopManager::MessageDispatch(), it == m_MsgMappingTable.end", 0);
return CLStatus(-1, 0);
}
CallBackForMessageLoop pFunction = it->second;
if(pFunction != 0)
return (m_pMessageObserver->*pFunction)(pMessage);
else
{
CLLog::WriteLogMsg("In CLMessageLoopManager::MessageDispatch(), pFunction==0", 0);
return CLStatus(-1, 0);
}
}
m_pMessageObserver成员变量指定与这个消息循环相关的处理函数提供者,供自己在MessageDispatch()中调用。
m_MsgMappingTable维护了从消息ID到处理函数的映射。
EnterMessageLoop中:
1.首先将参数转换为SLExecutiveInitialParameter结构(包含传进来的参数和一个能告诉消息发送者是否已经可以接收消息的信号)。
2.执行与具体队列类型相关的初始化工作。
3.调用m_pMessageObserver->Initialize(),注册消息处理函数。
在以上三步中,如果出现异常,要做相应的清理操作,并设置SLExecutiveInitialParameter结构的pNotifier成员为false。
如果通过,则设置SLExecutiveInitialParameter结构的pNotifier成员以告知发送方“可以发送了”。然后进入消息循环。
最后,接收到退出消息,调用与具体队列类型相关的Uninitialize()。
基于STL队列的消息循环管理器类“CLMsgLoopManagerForMsgQueue”
头文件:
#ifndef CLMsgLoopManagerForMsgQueue_H
#define CLMsgLoopManagerForMsgQueue_H
#include <string>
#include "CLMessageLoopManager.h"
class CLMessageQueue;
class CLMsgLoopManagerForMsgQueue : public CLMessageLoopManager
{
public:
/*
pMsgQueue和pMsgObserver均应从堆中分配,且不必显示调用delete
*/
CLMsgLoopManagerForMsgQueue(CLMessageObserver *pMsgObserver, const char* pstrThreadName);
virtual ~CLMsgLoopManagerForMsgQueue();
protected:
virtual CLStatus Initialize();
virtual CLStatus Uninitialize();
virtual CLMessage* WaitForMessage();
private:
CLMsgLoopManagerForMsgQueue(const CLMsgLoopManagerForMsgQueue&);
CLMsgLoopManagerForMsgQueue& operator=(const CLMsgLoopManagerForMsgQueue&);
private:
CLMessageQueue *m_pMsgQueue;
std::string m_strThreadName;
};
#endif
实现:
#include "CLMsgLoopManagerForMsgQueue.h"
#include "CLMessageQueue.h"
#include "CLExecutiveNameServer.h"
#include "CLThreadCommunicationByMsgQueue.h"
#include "CLLog.h"
CLMsgLoopManagerForMsgQueue::CLMsgLoopManagerForMsgQueue(CLMessageObserver *pMsgObserver, const char* pstrThreadName) : CLMessageLoopManager(pMsgObserver)
{
m_strThreadName = pstrThreadName;
m_pMsgQueue = new CLMessageQueue;
}
CLMsgLoopManagerForMsgQueue::~CLMsgLoopManagerForMsgQueue()
{
}
CLStatus CLMsgLoopManagerForMsgQueue::Initialize()
{
CLExecutiveNameServer *pNameServer = CLExecutiveNameServer::GetInstance();
if(pNameServer == 0)
{
delete m_pMsgQueue;
m_pMsgQueue = 0;
CLLog::WriteLogMsg("In CLMsgLoopManagerForMsgQueue::Initialize(), CLExecutiveNameServer::GetInstance error", 0);
return CLStatus(-1, 0);
}
CLStatus s = pNameServer->Register(m_strThreadName.c_str(), new CLThreadCommunicationByMsgQueue(m_pMsgQueue));
if(!s.IsSuccess())
{
delete m_pMsgQueue;
m_pMsgQueue = 0;
CLLog::WriteLogMsg("In CLMsgLoopManagerForMsgQueue::Initialize(), pNameServer->Register error", 0);
return CLStatus(-1, 0);
}
else
{
return CLStatus(0, 0);
}
}
CLStatus CLMsgLoopManagerForMsgQueue::Uninitialize()
{
CLExecutiveNameServer *pNameServer = CLExecutiveNameServer::GetInstance();
if(pNameServer == 0)
{
CLLog::WriteLogMsg("In CLMsgLoopManagerForMsgQueue::Uninitialize(), CLExecutiveNameServer::GetInstance error", 0);
return CLStatus(-1, 0);
}
return pNameServer->ReleaseCommunicationPtr(m_strThreadName.c_str());
}
CLMessage* CLMsgLoopManagerForMsgQueue::WaitForMessage()
{
if(m_pMsgQueue != 0)
{
return m_pMsgQueue->GetMessage();
}
return 0;
}
m_strThreadName成员使该类支持名字服务。
初始化和卸载工作只是完成了名字服务的相关工作。
四.消息机制与线程的结合
为了避免用户直接接触到消息队列,需要对进队操作进行封装;通信的线程都需要保持队列的指针,何时释放队列?由谁释放?
当有多个线程时,向哪个线程发送消息,希望使用更有意义的字符串而不是标识符来标识线程的消息队列。
所以,添加两个类"CLExecutiveCommunication"(接口)和"CLExecutiveNameServer"。
执行体通信接口"CLExecutiveCommunication"(接口):
头文件:
#ifndef CLExecutiveCommunication_H
#define CLExecutiveCommunication_H
#include "CLStatus.h"
class CLMessage;
class CLExecutiveCommunication
{
public:
CLExecutiveCommunication();
virtual ~CLExecutiveCommunication();
virtual CLStatus PostExecutiveMessage(CLMessage *pMessage) = 0;
private:
CLExecutiveCommunication(const CLExecutiveCommunication&);
CLExecutiveCommunication& operator=(const CLExecutiveCommunication&);
};
#endif
实现:
#include "CLExecutiveCommunication.h"
CLExecutiveCommunication::CLExecutiveCommunication()
{
}
CLExecutiveCommunication::~CLExecutiveCommunication()
{
}
由继承该接口的类负责对与具体实现相关的队列的操作,维护消息队列;使消息队列的管理操作从执行体中剥离出去。
尽管声明了PostExecutiveMessage(),但由于调用起来不方便(总是要先找到与执行体相关的CLExecutiveCommunication),实际上在外部已被CLExecutiveNameServer的同名函数代替 (由其在内部调用)。
执行体的名字服务器类“CLExecutiveNameServer”
头文件:
#ifndef CLExecutiveNameServer_H
#define CLExecutiveNameServer_H
#include <pthread.h>
#include <map>
#include <string>
#include "CLStatus.h"
#include "CLMutex.h"
class CLExecutiveCommunication;
class CLMessage;
struct SLExecutiveCommunicationPtrCount
{
CLExecutiveCommunication *pExecutiveCommunication;
unsigned int nCount;
};
class CLExecutiveNameServer
{
public:
/*
出错时,构造函数和析构函数可能会产生字符串类型异常
*/
CLExecutiveNameServer();
virtual ~CLExecutiveNameServer();
static CLExecutiveNameServer* GetInstance();
static CLStatus PostExecutiveMessage(const char* pstrExecutiveName, CLMessage *pMessage);
public:
CLStatus Register(const char* strExecutiveName, CLExecutiveCommunication *pExecutiveCommunication);
CLExecutiveCommunication* GetCommunicationPtr(const char* strExecutiveName);
CLStatus ReleaseCommunicationPtr(const char* strExecutiveName);
private:
CLExecutiveNameServer(const CLExecutiveNameServer&);
CLExecutiveNameServer& operator=(const CLExecutiveNameServer&);
static pthread_mutex_t *InitializeMutex();
private:
static CLExecutiveNameServer * volatile m_pNameServer;
static pthread_mutex_t *m_pMutex;
private:
std::map<std::string, SLExecutiveCommunicationPtrCount*> m_NameTable;
CLMutex m_MutexForNameTable;
};
#endif
实现:
#include "CLExecutiveNameServer.h"
#include "CLCriticalSection.h"
#include "CLLog.h"
#include "CLExecutiveCommunication.h"
#include "CLMessage.h"
CLExecutiveNameServer* volatile CLExecutiveNameServer::m_pNameServer = 0;
pthread_mutex_t *CLExecutiveNameServer::m_pMutex = CLExecutiveNameServer::InitializeMutex();
CLExecutiveNameServer::CLExecutiveNameServer()
{
}
CLExecutiveNameServer::~CLExecutiveNameServer()
{
}
CLStatus CLExecutiveNameServer::PostExecutiveMessage(const char* pstrExecutiveName, CLMessage *pMessage)
{
CLExecutiveNameServer *pNameServer = CLExecutiveNameServer::GetInstance();
if(pNameServer == 0)
{
CLLog::WriteLogMsg("In CLExecutiveNameServer::PostExecutiveMessage(), CLExecutiveNameServer::GetInstance error", 0);
delete pMessage;
return CLStatus(-1, 0);
}
CLExecutiveCommunication* pComm = pNameServer->GetCommunicationPtr(pstrExecutiveName);
if(pComm == 0)
{
CLLog::WriteLogMsg("In CLExecutiveNameServer::PostExecutiveMessage(), pNameServer->GetCommunicationPtr error", 0);
delete pMessage;
return CLStatus(-1, 0);
}
CLStatus s = pComm->PostExecutiveMessage(pMessage);
if(!s.IsSuccess())
{
CLLog::WriteLogMsg("In CLExecutiveNameServer::PostExecutiveMessage(), pComm->PostExecutiveMessage error", 0);
CLStatus s1 = pNameServer->ReleaseCommunicationPtr(pstrExecutiveName);
if(!s1.IsSuccess())
CLLog::WriteLogMsg("In CLExecutiveNameServer::PostExecutiveMessage(), pNameServer->ReleaseCommunicationPtr error", 0);
return CLStatus(-1, 0);
}
CLStatus s2 = pNameServer->ReleaseCommunicationPtr(pstrExecutiveName);
if(!s2.IsSuccess())
CLLog::WriteLogMsg("In CLExecutiveNameServer::PostExecutiveMessage(), pNameServer->ReleaseCommunicationPtr error", 0);
return CLStatus(0, 0);
}
CLStatus CLExecutiveNameServer::Register(const char* strExecutiveName, CLExecutiveCommunication *pExecutiveCommunication)
{
CLCriticalSection cs(&m_MutexForNameTable);
std::map<std::string, SLExecutiveCommunicationPtrCount*>::iterator it = m_NameTable.find(strExecutiveName);
if(it != m_NameTable.end())
{
delete pExecutiveCommunication;
CLLog::WriteLogMsg("In CLExecutiveNameServer::Register(), m_NameTable.find error", 0);
return CLStatus(-1, 0);
}
SLExecutiveCommunicationPtrCount *p = new SLExecutiveCommunicationPtrCount;
p->pExecutiveCommunication = pExecutiveCommunication;
p->nCount = 1;
m_NameTable[strExecutiveName] = p;
return CLStatus(0, 0);
}
CLExecutiveCommunication* CLExecutiveNameServer::GetCommunicationPtr(const char* strExecutiveName)
{
CLCriticalSection cs(&m_MutexForNameTable);
std::map<std::string, SLExecutiveCommunicationPtrCount*>::iterator it = m_NameTable.find(strExecutiveName);
if(it == m_NameTable.end())
{
CLLog::WriteLogMsg("In CLExecutiveNameServer::GetCommunicationPtr(), m_NameTable.find error", 0);
return 0;
}
it->second->nCount++;
return it->second->pExecutiveCommunication;
}
CLStatus CLExecutiveNameServer::ReleaseCommunicationPtr(const char* strExecutiveName)
{
CLCriticalSection cs(&m_MutexForNameTable);
std::map<std::string, SLExecutiveCommunicationPtrCount*>::iterator it = m_NameTable.find(strExecutiveName);
if(it == m_NameTable.end())
{
CLLog::WriteLogMsg("In CLExecutiveNameServer::ReleaseCommunicationPtr(), m_NameTable.find error", 0);
return CLStatus(-1, 0);
}
it->second->nCount--;
if(it->second->nCount == 0)
{
delete it->second->pExecutiveCommunication;
delete it->second;
m_NameTable.erase(it);
}
return CLStatus(0, 0);
}
pthread_mutex_t *CLExecutiveNameServer::InitializeMutex()
{
pthread_mutex_t *p = new pthread_mutex_t;
int r = pthread_mutex_init(p, 0);
if(r != 0)
{
delete p;
return 0;
}
return p;
}
CLExecutiveNameServer* CLExecutiveNameServer::GetInstance()
{
if(m_pNameServer == 0)
{
if(m_pMutex == 0)
return 0;
int r = pthread_mutex_lock(m_pMutex);
if(r != 0)
return 0;
if(m_pNameServer == 0)
{
m_pNameServer = new CLExecutiveNameServer;
}
r = pthread_mutex_unlock(m_pMutex);
if(r != 0)
return 0;
}
return m_pNameServer;
}
该类与CLLog类一样,使用了单件模式SLExecutiveCommunicationPtrCountSLExecutiveCommunicationPtrCountCLExecutiveCommunication和一个引用计数器Register()先查找有没有重名的执行体,若名称已存在,返回错误;否则,将执行体的CLExecutiveCommunication和名字添加到映射,并置其引用计数为1。
GetCommunicationPtr()获取执行体的CLExecutiveCommunication,这意味着将要向其发送消息,故将其引用计数加1。
ReleaseCommunicationPtr()一般在发送完消息后调用,将其引用计数减1;此时,若引用计数=0了,表明该队列已无人访问,可以清除。故执行体在退出前应执行ReleaseCommunicationPtr()清理自己的消息队列。
这两个函数对类的共享映射结构做操作,所以必须将他们的函数体放在临界区中。
PostExecutiveMessage()静态函数负责向指定名字的消息队列发送消息,就是简单调用CLExecutiveCommunication的PostExecutiveMessage()和自己的ReleaseCommunicationPtr()。
看下实现了CLExecutiveCommunication的线程的消息队列通信类“CLThreadCommunicationByMsgQueue”
头文件:
#ifndef CLThreadCommunicationByMsgQueue_H
#define CLThreadCommunicationByMsgQueue_H
#include "CLExecutiveCommunication.h"
#include "CLStatus.h"
class CLMessage;
class CLMessageQueue;
class CLThreadCommunicationByMsgQueue : public CLExecutiveCommunication
{
public:
/*
pMsgQueue必须从堆中分配,且不必显示调用delete
*/
CLThreadCommunicationByMsgQueue(CLMessageQueue *pMsgQueue);
virtual ~CLThreadCommunicationByMsgQueue();
virtual CLStatus PostExecutiveMessage(CLMessage *pMessage);
private:
CLThreadCommunicationByMsgQueue(const CLThreadCommunicationByMsgQueue&);
CLThreadCommunicationByMsgQueue& operator=(const CLThreadCommunicationByMsgQueue&);
private:
CLMessageQueue *m_pMsgQueue;
};
#endif
实现:
#include "CLThreadCommunicationByMsgQueue.h"
#include "CLMessageQueue.h"
#include "CLMessage.h"
CLThreadCommunicationByMsgQueue::CLThreadCommunicationByMsgQueue(CLMessageQueue *pMsgQueue)
{
m_pMsgQueue = pMsgQueue;
}
CLThreadCommunicationByMsgQueue::~CLThreadCommunicationByMsgQueue()
{
if(m_pMsgQueue != 0)
delete m_pMsgQueue;
}
CLStatus CLThreadCommunicationByMsgQueue::PostExecutiveMessage(CLMessage *pMessage)
{
if(m_pMsgQueue == 0)
{
delete pMessage;
return CLStatus(-1, 0);
}
return m_pMsgQueue->PushMessage(pMessage);
}
构造函数接收线程的消息队列指针作为参数,从此线程将消息队列的管理权交给CLThreadCommunicationByMsgQueue对象。析构函数负责清理队列。
五.若新执行体的消息队列尚未创建完成,或者线程尚未注册名字服务时,发送发就已经发送了消息,就会丢失消息。
所以,应该同步发送发和新执行体,待新执行体完成初始化后再发送。为此,创建了
执行体初始化完成标识类“CLExecutiveInitialFinishedNotifier”(接口)
头文件:
#ifndef CLExecutiveInitialFinishedNotifier_H
#define CLExecutiveInitialFinishedNotifier_H
#include "CLStatus.h"
class CLExecutiveInitialFinishedNotifier
{
public:
CLExecutiveInitialFinishedNotifier();
virtual ~CLExecutiveInitialFinishedNotifier();
virtual CLStatus NotifyInitialFinished(bool bInitialSuccess) = 0;
virtual bool IsInitialSuccess() = 0;
private:
CLExecutiveInitialFinishedNotifier(const CLExecutiveInitialFinishedNotifier&);
CLExecutiveInitialFinishedNotifier& operator=(const CLExecutiveInitialFinishedNotifier&);
};
#endif
实现:
#include "CLExecutiveInitialFinishedNotifier.h"
CLExecutiveInitialFinishedNotifier::CLExecutiveInitialFinishedNotifier()
{
}
CLExecutiveInitialFinishedNotifier::~CLExecutiveInitialFinishedNotifier()
{
}
其线程实现“CLThreadInitialFinishedNotifier”
头文件:
#ifndef CLThreadInitialFinishedNotifier_H
#define CLThreadInitialFinishedNotifier_H
#include "CLExecutiveInitialFinishedNotifier.h"
class CLEvent;
class CLThreadInitialFinishedNotifier : public CLExecutiveInitialFinishedNotifier
{
public:
CLThreadInitialFinishedNotifier(CLEvent *pEvent);
virtual ~CLThreadInitialFinishedNotifier();
virtual CLStatus NotifyInitialFinished(bool bInitialSuccess);
virtual bool IsInitialSuccess();
private:
CLThreadInitialFinishedNotifier(const CLThreadInitialFinishedNotifier&);
CLThreadInitialFinishedNotifier& operator=(const CLThreadInitialFinishedNotifier&);
private:
bool m_bSuccess;
CLEvent *m_pEvent;
};
#endif
实现:
#include "CLThreadInitialFinishedNotifier.h"
#include "CLEvent.h"
#include "CLLog.h"
CLThreadInitialFinishedNotifier::CLThreadInitialFinishedNotifier(CLEvent *pEvent)
{
m_pEvent = pEvent;
m_bSuccess = false;
}
CLThreadInitialFinishedNotifier::~CLThreadInitialFinishedNotifier()
{
}
CLStatus CLThreadInitialFinishedNotifier::NotifyInitialFinished(bool bInitialSuccess)
{
m_bSuccess = bInitialSuccess;
if(m_pEvent == 0)
return CLStatus(-1, 0);
CLStatus s = m_pEvent->Set();
if(!s.IsSuccess())
{
CLLog::WriteLogMsg("In CLThreadInitialFinishedNotifier::NotifyInitialFinished(), m_pEvent->Set error", 0);
return CLStatus(-1, 0);
}
return CLStatus(0, 0);
}
bool CLThreadInitialFinishedNotifier::IsInitialSuccess()
{
return m_bSuccess;
}
接收一个CLEvent指针作为参数,在执行体初始化成功或失败后NotifyInitialFinished(),唤醒等待的发送者,发送者再依据IsInitialSuccess()查询状态。
最后,为了简化线程创建及其相关的队列,消息处理函数,消息后循环等对象的过程,构造一个CLThreadProxy完成这些过程。
头文件:
#ifndef CLThreadProxy_H
#define CLThreadProxy_H
#include "CLStatus.h"
class CLMessageObserver;
class CLThread;
/*
该类用于创建一个线程,其采用的通信机制是CLMessageQueue。
*/
class CLThreadProxy
{
public:
/*
pMsgObserver应从堆中分配,且不必调用delete,pstrThreadName所代表的线程名称必须是唯一的
默认情况下bWaitForDeath为false,若为true,则会在析构函数中等待新线程死亡
*/
CLThreadProxy(CLMessageObserver *pMsgObserver, const char *pstrThreadName);
CLThreadProxy(CLMessageObserver *pMsgObserver, const char *pstrThreadName, bool bWaitForDeath);
virtual ~CLThreadProxy();
/*
Run方法无论返回正确或出错,均只可调用一次。否则,另建一个CLThreadProxy对象
*/
CLStatus Run(void *pContext);
private:
CLThreadProxy(const CLThreadProxy&);
CLThreadProxy& operator=(const CLThreadProxy&);
private:
CLThread *m_pThread;
bool m_bWaitForDeath;
};
#endif
实现:
#include "CLThreadProxy.h"
#include "CLThread.h"
#include "CLExecutiveFunctionForMsgLoop.h"
#include "CLMsgLoopManagerForMsgQueue.h"
#include "CLLog.h"
#include "CLThreadInitialFinishedNotifier.h"
#include "CLEvent.h"
CLThreadProxy::CLThreadProxy(CLMessageObserver *pMsgObserver, const char *pstrThreadName)
{
m_bWaitForDeath = false;
m_pThread = new CLThread(new CLExecutiveFunctionForMsgLoop(new CLMsgLoopManagerForMsgQueue(pMsgObserver, pstrThreadName)));
}
CLThreadProxy::CLThreadProxy(CLMessageObserver *pMsgObserver, const char *pstrThreadName, bool bWaitForDeath)
{
m_bWaitForDeath = bWaitForDeath;
m_pThread = new CLThread(new CLExecutiveFunctionForMsgLoop(new CLMsgLoopManagerForMsgQueue(pMsgObserver, pstrThreadName)), bWaitForDeath);
}
CLThreadProxy::~CLThreadProxy()
{
if((m_bWaitForDeath) && (m_pThread != 0))
{
CLStatus s = m_pThread->WaitForDeath();
if(!s.IsSuccess())
CLLog::WriteLogMsg("In CLThreadProxy::~CLThreadProxy(), m_pThread->WaitForDeath error", 0);
}
}
CLStatus CLThreadProxy::Run(void *pContext)
{
if(m_pThread == 0)
return CLStatus(-1, 0);
CLEvent event;
CLThreadInitialFinishedNotifier notifier(&event);
SLExecutiveInitialParameter para;
para.pContext = pContext;
para.pNotifier = ¬ifier;
CLStatus s = m_pThread->Run(¶);
if(!s.IsSuccess())
{
CLLog::WriteLogMsg("In CLThreadProxy::Run(), m_pThread->Run error", 0);
m_bWaitForDeath = false;
m_pThread = 0;
return CLStatus(-1, 0);
}
CLStatus s1 = event.Wait();
if(!s1.IsSuccess())
CLLog::WriteLogMsg("In CLThreadProxy::Run(), event.Wait error", 0);
if(notifier.IsInitialSuccess())
return CLStatus(0, 0);
else
return CLStatus(-1, 0);
}
event.Wait()等待线程初始化完成。
当不想创建新线程,而是让主线程进入消息后循环时“CLNonThreadProxy”
#ifndef CLNonThreadProxy_H
#define CLNonThreadProxy_H
#include "CLStatus.h"
class CLMessageObserver;
class CLExecutiveFunctionProvider;
/*
该类用于让线程直接进入消息循环,而不是创建新线程
*/
class CLNonThreadProxy
{
public:
/*
pMsgObserver应从堆中分配,且不必调用delete,pstrThreadName所代表的线程名称必须是唯一的
*/
CLNonThreadProxy(CLMessageObserver *pMsgObserver, const char *pstrThreadName);
virtual ~CLNonThreadProxy();
CLStatus Run(void *pContext);
private:
CLNonThreadProxy(const CLNonThreadProxy&);
CLNonThreadProxy& operator=(const CLNonThreadProxy&);
private:
CLExecutiveFunctionProvider *m_pFunctionProvider;
};
#endif
实现:
#include "CLNonThreadProxy.h"
#include "CLExecutiveFunctionForMsgLoop.h"
#include "CLMsgLoopManagerForMsgQueue.h"
#include "CLLog.h"
#include "CLThreadInitialFinishedNotifier.h"
CLNonThreadProxy::CLNonThreadProxy(CLMessageObserver *pMsgObserver, const char *pstrThreadName)
{
m_pFunctionProvider = new CLExecutiveFunctionForMsgLoop(new CLMsgLoopManagerForMsgQueue(pMsgObserver, pstrThreadName));
}
CLNonThreadProxy::~CLNonThreadProxy()
{
if(m_pFunctionProvider != 0)
delete m_pFunctionProvider;
}
CLStatus CLNonThreadProxy::Run(void *pContext)
{
if(m_pFunctionProvider == 0)
return CLStatus(-1, 0);
CLThreadInitialFinishedNotifier notifier(0);
SLExecutiveInitialParameter para;
para.pContext = pContext;
para.pNotifier = ¬ifier;
return m_pFunctionProvider->RunExecutiveFunction(¶);
}
由于是自己的,所以不必等待初始化,只要按序执行就可以了。