from: http://groups.csdn.net/boost_asio
通常我們使用線程的時候會有這樣的操作
在a線程空間中將事件交給b線程處理:
b.PostMessage();
這個操作是異步的,所以要傳給b線程的數據不能在棧上分配,而應該在堆上分配.
見下面的例子
void func()
{
A a;
b.PostMessage(nMsg, &a, 0);
}
上面的例子因為a在棧上分配,當func()函數退出的時候,a的析構函數將被調用,a的占用的地址成為了一個無效的地址.
在以后的某個時候,當b線程式要處理這個消息的時候,用了一個無效的地址,這個時候異常就發生了.
所以通常這樣做:
void func()
{
A *pa = new A();
b.PostMessage(MSG_POST, pa, 0);
}
這樣做解決了上面的問題,因為pa是在堆上new出來的,所以直到你調用 delete, pa才會析構.
但是如果只是這樣的話,那么會出現內存泄漏.因此要在處理消息后, 調用delete.
void ProcessMessage(unsignd nMsg, WPARAM wParam, LPARAM lParam)
{
if (nMsg == MSG_POST)
{
A *pa = (A*)wParam;
do_something (pa);
delete pa;
}
}
這樣做解決了內存泄漏的問題 .但是要人為地去管理pa的生命周期,而且容易忘記調用nMsg而產生內存泄漏.
所以也不是很好的做法.
我們有沒有一種辦法讓我們不用去管理這個pa的生命周期呢?
我們通過使用boost的異質容器類any和管理指針生命周期的shared_ptr來實現這一點.
struct CCommand
{
typedef bst::shared_ptr<CCommand> CCmdPtr;
unsigned int nCmd;
bst::any anyParam;
};
這是一個消息對象, nCmd是消息類型, anyParam存儲要傳遞的數據.它可以接受任何類型的數據.
我們實現一個ThreadEx類:
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)
{//記錄出錯日志,退出線程
}
}
}
private:
std::list<CCommand::CCmdPtr> m_lstCmd;
bst::mutex m_mutex;
};
在PostCommand這個函數中,我們規定了第二個參數一定是一個shared_ptr類型的智能指針.之所以要這樣做,是希望
在編譯期提醒程序員一定要使用shared_ptr類型的對象作為參數.
我們像這樣使用:
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();
}