线程模型简介
传统的回调机制,可控性差、容易导致死锁等问题。本模块采用异步任务机制,通过command模式,可以很好的进行多线程的协作,避免使用共享变量、加锁,有效的防止死锁与其他多线程安全问题。
实现上使用了 libjingle 库。(注:原来使用了 chrome base 的线程库,两者实现原理一致,但 libjingle 使用上方便一些。)
把要异步执行的任务信息封装在 Message 数据结构中,Post 或 PostDelay 到相应的线程去执行。在该线程执行完之后,如果需要通知发起线程,则再 Post 回原来的线程。每个线程都有自己的消息队列,线程不停地从队列中取出 Message 执行相应的任务。
多线程之间数据共享:
thread_A (data_A),thread_B(data_B)
从thread_A转到thread_B,在thread_A中调用:
thread_B->post(handler,msg_id,new data_B(data_A,len))
根据data_A,拷贝一份数据data_B,任务执行完毕后,释放拷贝数据data_B
注意:为了简要说明,下方代码省去了线程内部message_queue的锁操作(线程安全)。
线程模型:
class MessageHandler {
public:
virtual ~MessageHandler();
virtual void OnMessage(Message* msg) = 0;
protected:
MessageHandler() {}
private:
DISALLOW_COPY_AND_ASSIGN(MessageHandler);
};
class MessageData {
public:
MessageData() {}
virtual ~MessageData() {}
};
struct Message {
MessageHandler *phandler;
uint32 message_id;
MessageData *pdata;
uint32 ts_sensitive;
};
typedef std::list<Message> MessageList;
class MessageQueue {
virtual bool Get(Message *pmsg, int cmsWait = kForever,
bool process_io = true) {
*pmsg = msgq_.front();
msgq_.pop_front();
}
virtual void Post(MessageHandler *phandler, uint32 id = 0,
MessageData *pdata = NULL, bool time_sensitive = false) {
Message msg;
msg.phandler = phandler;
msg.message_id = id;
msg.pdata = pdata;
msgq_.push_back(msg);
}
virtual void Dispatch(Message *pmsg) {
pmsg->phandler->OnMessage(pmsg);
}
protected:
MessageList msgq_;
}
class Thread : public MessageQueue {
public:
bool Start(Runnable* runnable = NULL) {
// 在各个平台上分别,通过调用底层API来创建线程,PreRun是线程函数执行体
#if defined(WIN32)
thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PreRun, init, flags,
&thread_id_);
#elif defined(POSIX)
pthread_create(&thread_, &attr, PreRun, init);
return true;
}
void Run() {
ProcessMessages(kForever);
}
bool ProcessMessages(int cms) {
Message msg;
if (!Get(&msg, cmsNext))
return !IsQuitting();
Dispatch(&msg);
}
private:
static void *PreRun(void *pv) {
Run();
}
#ifdef POSIX
pthread_t thread_;
#endif
#ifdef WIN32
HANDLE thread_;
DWORD thread_id_;
#endif
};