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();
}