注意deadline_timer和socket一樣,都用 io_service作為構(gòu)造函數(shù)的參數(shù)。也即,在其上進(jìn)行異步操作,都將導(dǎo)致和io_service所包含的iocp相關(guān)聯(lián)。這同樣意味著在析構(gòu) io_service之前,必須析構(gòu)關(guān)聯(lián)在這個(gè)io_service上的deadline_timer。
一個(gè)deadline_timer只維護(hù)一個(gè)超時(shí)時(shí)間,一個(gè)deadline_timer不同時(shí)維持多個(gè)定時(shí)器。
void wait();
void wait(boost::system::error_code & ec);
這是個(gè)同步等待函數(shù),例如:
boost::asio::io_service io;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
t.wait();
由于不涉及到異步,該函數(shù)和io_service沒(méi)什么關(guān)系。這個(gè)函數(shù)在windows下的實(shí)現(xiàn)就只是簡(jiǎn)單的Sleep。因此也就不存在cancel之說(shuō)。
如果t的expire時(shí)間已過(guò),那么t.wait會(huì)立刻返回。
例如如下代碼:
boost::asio::io_service io;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
t.wait();
t.wait();
第一個(gè)t.wait會(huì)等待5s才返回,第2個(gè)t.wait會(huì)立刻返回。
wait函數(shù)本身沒(méi)有參數(shù),不存在t.wait(seconds(5))的用法。
可以在構(gòu)造deadline_timer時(shí)指定時(shí)間。
basic_deadline_timer(
boost::asio::io_service & io_service);
basic_deadline_timer(
boost::asio::io_service & io_service,
const time_type & expiry_time);
basic_deadline_timer(
boost::asio::io_service & io_service,
const duration_type & expiry_time);
注意后兩種的區(qū)別。以下2種用法是等價(jià)的:
boost::asio::deadline_timer t(io, boost::posix_time::microsec_clock::universal_time()+boost::posix_time::seconds(5));
boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
前者是絕對(duì)時(shí)間,后者是相對(duì)時(shí)間。
除了在deadline_timer構(gòu)造函數(shù)中指定時(shí)間,也可以使用如下2個(gè)函數(shù)指定時(shí)間:
expires_at,expires_from_now。這兩個(gè)函數(shù)的區(qū)別是前者參數(shù)是絕對(duì)時(shí)間,后者是相對(duì)時(shí)間。例如:
boost::asio::io_service io;
boost::asio::deadline_timer t(io);
t.expires_from_now(boost::posix_time::seconds(5));
t.wait();
注意這兩個(gè)函數(shù)除了設(shè)定下次超時(shí)時(shí)間之外,還有一個(gè)效果是取消前面所有的異步wait。詳情參看關(guān)于這兩個(gè)函數(shù)的詳細(xì)解釋。
template<
typename WaitHandler>
void async_wait(
WaitHandler handler);
其中void handler(
const boost::system::error_code& error // Result of operation.
);
注意這個(gè)error很重要,表明這個(gè)handler是因?yàn)槌瑫r(shí)被執(zhí)行還是因?yàn)楸籧ancel。
符合2種情況之一,handler被執(zhí)行:超時(shí)或者被cancel。
這同時(shí)隱含的說(shuō)明了除非io.stop被調(diào)用,否則handler一定會(huì)被執(zhí)行。即便是被cancel。
被cancel有多種方法,直接調(diào)用cancel或者調(diào)用expires_at,expires_from_now重新設(shè)置超時(shí)時(shí)間。
void handle_wait(const boost::system::error_code& error,
boost::asio::deadline_timer& t,int& count)
{
if(!error)
{
std::cout<< count<<"\n";
if(count++<5)
{
t.expires_from_now(boost::posix_time::seconds(1));
t.async_wait(boost::bind(handle_wait,boost::asio::placeholders::error,
boost::ref(t),boost::ref(count)));
}
}
}
int main()
{
boost::asio::io_service io;
boost::asio::deadline_timer t(io);
size_t a = t.expires_from_now(boost::posix_time::seconds(1));
int count = 0;
t.async_wait(boost::bind(handle_wait,boost::asio::placeholders::error,
boost::ref(t),boost::ref(count)));
io.run();
return 0;
}
deadline_timer的析構(gòu)函數(shù)什么也不做,因此不會(huì)導(dǎo)致發(fā)出的async_wait被cancel。
std::size_t cancel();
std::size_t cancel(
boost::system::error_code & ec);
此函數(shù)調(diào)用會(huì)導(dǎo)致所有尚未返回的async_wait(handler)的handler被調(diào)用,同時(shí)error_code為boost::asio::error::operation_aborted。返回值是被cancel的timer數(shù)量。
time_type expires_at() const;
std::size_t expires_at(
const time_type & expiry_time);
std::size_t expires_at(
const time_type & expiry_time,
boost::system::error_code & ec);
duration_type expires_from_now() const;
std::size_t expires_from_now(
const duration_type & expiry_time);
std::size_t expires_from_now(
const duration_type & expiry_time,
boost::system::error_code & ec); 以上2組函數(shù)用來(lái)設(shè)置新的超時(shí)時(shí)間,同時(shí)cancel所有未完成的async_wait操作。注意這兩個(gè)函數(shù)的返回值即為cancel的操作數(shù)量。
考慮如下場(chǎng)景,我們有一個(gè)workerthread正在調(diào)用io_work.run();
此時(shí)主線(xiàn)程向workerthread發(fā)出了一個(gè)異步調(diào)用,例如post(...),考慮到io_work.run很可能積壓了很多handlers沒(méi)有處理,或者某些handlers處理非常耗時(shí),希望它在5s內(nèi)必須返回。那么可以:
void handle_wait(const boost::system::error_code& error,bool& Ret)
{
if(!error) Ret = false;
}
void handle_func(
boost::shared_ptr<boost::asio::deadline_timer> t,
boost::shared_ptr<boost::asio::io_service> io,
int* v)
{
boost::asio::io_service::work work(*io);
if(t->cancel()>0)
{
*v = 1;
}
}
void func_delay_1_second()
{
boost::asio::io_service io;
boost::asio::deadline_timer t(io,boost::posix_time::seconds(1));
t.wait();
}
bool sync_func(int& v,boost::asio::io_service& io_work)
{
boost::shared_ptr<boost::asio::io_service> io(new boost::asio::io_service);
boost::shared_ptr<boost::asio::deadline_timer> t(new boost::asio::deadline_timer(*io));
t->expires_from_now(boost::posix_time::seconds(5));
bool ret = true;
t->async_wait(boost::bind(handle_wait,boost::asio::placeholders::error,boost::ref(ret)));
io_work.post(boost::bind(handle_func,t,io,&v));
io->run();
return ret;
}
int main()
{
boost::asio::io_service io_work;
auto_ptr<boost::asio::io_service::work> work(new boost::asio::io_service::work(io_work));
boost::thread workthread(boost::bind(&boost::asio::io_service::run, &io_work));
for(int i=0;i<3;++i) io_work.post(func_delay_1_second);
int v = 0;
bool ret = sync_func(v,io_work);
if(ret) printf("v %d\n",v);
work.reset();
workthread.join();
return 0;
}
上面代碼中如果先進(jìn)入handle_wait,則表明超時(shí),此時(shí)設(shè)置ret = false,然后io.run會(huì)退出,表明調(diào)用失敗,如果稍后進(jìn)入handle_func,則t->cancel會(huì)返回0,也不做任何操作。雖然在 io.run退出時(shí)會(huì)釋放v,但由于handle_func不做任何操作因此也不會(huì)引起任何安全問(wèn)題。如果handle_func先進(jìn)入,則首先使用 work讓io.run不會(huì)退出,然后取消timer,并且設(shè)置,隨后work析構(gòu),io.run會(huì)退出。注意這里面的同步問(wèn)題:如果先進(jìn)入 handle_wait,隨后進(jìn)入handle_func,那么handle_func中的t->cancel會(huì)返回0從而不做任何事。如果先進(jìn)入 handle_func,隨后進(jìn)入handle_wait,那么t->cancel或者返回0或者返回1,由于使用了work,io.run也不會(huì) 退出。注意這里的t和io都是shared_ptr的,否則因?yàn)槿绻鹔andle_wait先返回,則io.run會(huì)立刻退出并析 構(gòu),handle_func中將使用懸空的t和io,將導(dǎo)致非法操作。注意這里的io必須是shared_ptr的,如果 boost::asio::io_service::work work(*io); 改成work(t->get_ioservice());則t是有效的,而t所索引的io_service已經(jīng)無(wú)效了,同樣會(huì)導(dǎo)致非法操作。牢記 io_service的使用原則:必須首先析構(gòu)所有索引的其他對(duì)象之后才能析構(gòu)io_service。