网上大部分人都讲boost.asio用完成端口实现,并且实现了线程池,所以效率非常的高。
我在应用asio的时候发现完成端口是有,但是线程池确并不存在,而且在现有的架构下,要想用线程池来实现对数据的处理,可能写出来不是很好看。
asio通过开启线程调用io_service::run再调用win_iocp_io_service::run来处理收到的事件。
size_t run(boost::system::error_code& ec)
{
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
{
ec = boost::system::error_code();
return 0;
}
call_stack<win_iocp_io_service>::context ctx(this);
size_t n = 0;
while (do_one(true, ec))
if (n != (std::numeric_limits<size_t>::max)())
++n;
return n;
}
do_one里面为
BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
&completion_key, &overlapped, block ? timeout : 0);
operation* op = static_cast<operation*>(overlapped);
op->do_completion(last_error, bytes_transferred);
实际上如果op->do_completion里面有时间比较长的操作,这个线程同样为死在这个地方。
因为只有一个线程在驱动前面的run函数。
当然你也可以通过同时启动几个线程来调用run函数,这样是可行的,但是这种手法确很笨拙,因为你可能一下启动10个线程,却只有一个线程比较忙,
或者你的10个线程根本就忙不过来,这根有没有使用iocp完全没什么两样。
做事情要力求完美,不要以为NB的大师不提供的东西,你就不能自已弄一个。其实我觉得asio里面c++的运用,非常的完美,但是从实用的角度来说,
还不如我以前一个同事写的iocp写得好。
我们怎么对asio这部分进行改良,让他支持线程池的方式呢。
实际上我们只需要对win_iocp_io_service进行一些加工即可。
在do_one里面
op->do_completion(last_error, bytes_transferred);
之前auto_work work(*this);
这个地方,实际上就是来计算当前有多少工作要做,
这个地方调用work_started
::InterlockedIncrement(&outstanding_work_);
只需要在这按照你的需求加入一个线程就可以了。
算法自已想吧,还存在work_finished函数,可以用来减少线程。
需要给win_iocp_io_service类增加一个
thread_group成员变量,供上面使用。
改良的方式不是很好,也比较不好看,
唉,完美只存在心里,适可而止吧。
lixiaomail
2008-08-05