from: http://groups.csdn.net/boost_asio
通常我們使用線程的時(shí)候會(huì)有這樣的操作
在a線程空間中將事件交給b線程處理:
b.PostMessage();
這個(gè)操作是異步的,所以要傳給b線程的數(shù)據(jù)不能在棧上分配,而應(yīng)該在堆上分配.
見(jiàn)下面的例子
void func()
{
A a;
b.PostMessage(nMsg, &a, 0);
}
上面的例子因?yàn)閍在棧上分配,當(dāng)func()函數(shù)退出的時(shí)候,a的析構(gòu)函數(shù)將被調(diào)用,a的占用的地址成為了一個(gè)無(wú)效的地址.
在以后的某個(gè)時(shí)候,當(dāng)b線程式要處理這個(gè)消息的時(shí)候,用了一個(gè)無(wú)效的地址,這個(gè)時(shí)候異常就發(fā)生了.
所以通常這樣做:
void func()
{
A *pa = new A();
b.PostMessage(MSG_POST, pa, 0);
}
這樣做解決了上面的問(wèn)題,因?yàn)閜a是在堆上new出來(lái)的,所以直到你調(diào)用 delete, pa才會(huì)析構(gòu).
但是如果只是這樣的話,那么會(huì)出現(xiàn)內(nèi)存泄漏.因此要在處理消息后, 調(diào)用delete.
void ProcessMessage(unsignd nMsg, WPARAM wParam, LPARAM lParam)
{
if (nMsg == MSG_POST)
{
A *pa = (A*)wParam;
do_something (pa);
delete pa;
}
}
這樣做解決了內(nèi)存泄漏的問(wèn)題 .但是要人為地去管理pa的生命周期,而且容易忘記調(diào)用nMsg而產(chǎn)生內(nèi)存泄漏.
所以也不是很好的做法.
我們有沒(méi)有一種辦法讓我們不用去管理這個(gè)pa的生命周期呢?
我們通過(guò)使用boost的異質(zhì)容器類(lèi)any和管理指針生命周期的shared_ptr來(lái)實(shí)現(xiàn)這一點(diǎn).
struct CCommand
{
typedef bst::shared_ptr<CCommand> CCmdPtr;
unsigned int nCmd;
bst::any anyParam;
};
這是一個(gè)消息對(duì)象, nCmd是消息類(lèi)型, anyParam存儲(chǔ)要傳遞的數(shù)據(jù).它可以接受任何類(lèi)型的數(shù)據(jù).
我們實(shí)現(xiàn)一個(gè)ThreadEx類(lèi):
class CThreadEx
{
public:
typedef boost::singal<void(const CCommand&)> CommandProcessor;
CommandProcessor m_cmdProc;
CThreadEx();
~CThreadEx();
template<typename T>
void PostCommand(unsigned nCmd, const bst::shared_ptr<T>& p)
{
bst::mutex::scoped_lock lock(m_mutex);
CCommand::CCmdPtr cmd(new CCommand);
cmd->nCmd = nCmd;
cmd->anyParam = p;
m_lstCmd.push_back(cmd);
}
template<typename T>
void SendCommand(unsigned nCmd, const bst::shared_ptr<T>& p);
protected:
virtual void ProcessCommand(const CCommand& cmd)
private:
void ThreadRoutine()
{
while(1)
CommandLoop();
}
void CommandLoop()
{
bst::mutex::scoped_lock lock(m_mutex);
while (!m_lstCmd.empty())
{
CCommand::CCmdPtr cmd = m_lstCmd.front();
m_lstCmd.pop_front();
try
{
if (!m_cmdProc.empty())
m_cmdProc(*cmd);
}
catch(boost::bad_any_cast& e)
{//記錄出錯(cuò)日志,退出線程
}
}
}
private:
std::list<CCommand::CCmdPtr> m_lstCmd;
bst::mutex m_mutex;
};
在PostCommand這個(gè)函數(shù)中,我們規(guī)定了第二個(gè)參數(shù)一定是一個(gè)shared_ptr類(lèi)型的智能指針.之所以要這樣做,是希望
在編譯期提醒程序員一定要使用shared_ptr類(lèi)型的對(duì)象作為參數(shù).
我們像這樣使用:
class CMyThread
{
CThreadEx m_thread;
public:
CMyThread()
{
m_thread.m_cmdProc.Connect(boost::bind(&CMyThread::ProcessCommand, this, _1));
}
void ProcessCommand(const CCommand& cmd)
{
if (cmd.nCmd == 1)
{
bst::shared_ptr<int> n = boost::any_cast<bst::shared_ptr<int> >(cmd.anyParam);
std::cout << *n <<std::endl;
}
}
void AsyncProcess()
{
bst::shared_ptr<int> pInt(new int);
*pInt = 8;
m_thread.PostCommand(1, pInt);
}
};
void main()
{
CMyThread th;
th.AsyncProcess();
boost::thread::yield();
}