Boost::asio::deadline_timer 定時器詳解

1.Timer.1 - 使用同步定時器

先完整介紹一下,后面的例子該省略的就省略了嗤栓。
所有的Asio類只要簡單的包含"asio.hpp"頭文件便可使用:
#include <boost/asio.hpp>
因為本程序中使用了定時器,我們需要包含相應的的Boost.Date_Time 頭文件來處理時間操作:
#include <boost/date_time/posix_time/posix_time.hpp>
使用Asio的所有程序都至少需要一個提供訪問I/O功能的io_service 對象茫因。因此在主函數(shù)中我們做的第一件事就是聲明一個這個類型的對象:
boost::asio::io_service io;
接下來我們聲明一個boost::asio::deadline_timer類型的對象痰娱。作為 Asio的核心類,它提供的I/O功能(在此為定時器功能)通常用一個io_service 的引用作為其構(gòu)造函數(shù)的第一個參數(shù)箍铲。第二個參數(shù)設置一個從現(xiàn)在開始5秒后終止的定時器雇卷。
boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
可以看一下boost::asio::deadline_timer的幾個構(gòu)造函數(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種用法是等價的:

1 boost::asio::deadline_timer t(io, boost::posix_time::microsec_clock::universal_time()+boost::posix_time::seconds(5));  
2 boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));  

在這個簡單的程序中颠猴,我們用定時器演示一個阻塞等待关划。deadline_timer::wait() 函數(shù)調(diào)用直到定時器終止(從定時器被創(chuàng)建算起,五秒后終止)才會返回翘瓮。
一個deadline timer 通常是下面兩種狀態(tài)中的一種:"expired(終止)" 或"not expired(不終止)"贮折。如果deadline_timer::wait() 函數(shù)被一個已經(jīng)終止的定時器調(diào)用, 它將立即返回资盅。
t.wait();
最后我們打印出 "Hello, world!" 信息以顯示定時器已經(jīng)終止调榄。
std::cout << "Hello, world!\n";
代碼:

#include <iostream>  
#include <boost/asio.hpp>  
#include <boost/date_time/posix_time/posix_time.hpp>  
int main()  
{  
  boost::asio::io_service io;  
  boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));  
  t.wait();  
  std::cout << "Hello, world!\n";  
  return 0;  
}

2. Timer.2 - 使用異步定時器

本例使用Asio的異步回調(diào)功能在定時器中演示一個異步等待踊赠。

使用Asio的異步功能意味著當一個異步操作完成時一個回調(diào)函數(shù)將被調(diào)用。在本程序中我們定義一個名為print 的函數(shù)每庆,在異步等待結(jié)束后這個函數(shù)將被調(diào)用筐带。

void print(const boost::system::error_code& /*e*/)
{
  std::cout << "Hello, world!\n";
}
int main()
{
  boost::asio::io_service io;
  boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
}

接下來,我們調(diào)用 deadline_timer::async_wait() 函數(shù)執(zhí)行一個異步等待去取代Timer.1例中的阻塞等待缤灵。當調(diào)用這個函數(shù)時我們傳入上面定義的print回調(diào)句柄伦籍。
t.async_wait(print);
最后,我們必須在io_service對象上調(diào)用io_service::run()成員函數(shù)腮出。
Asio保證回調(diào)句柄僅僅能被io_service::run()啟動的當前線程所調(diào)用鸽斟。 因此桅狠,如果io_service::run() 函數(shù)不執(zhí)行厦凤,用于異步等待完成時的回調(diào)函數(shù)(在本例中為print函數(shù))將永遠不會被調(diào)用。
當仍舊有“工作”可做時尚镰,io_service::run() 函數(shù)會繼續(xù)運行慢逾。在本例中立倍,“工作”是定時器的異步等待,因此侣滩,直到定時器終止和回調(diào)函數(shù)執(zhí)行完成口注,程序才會返回。
在調(diào)用io_service::run()之前確保給 io_service 一些工作去做君珠,這非常重要寝志。 例如,如果我們省略了上面調(diào)用的deadline_timer::async_wait() 函數(shù)策添,io_service對象將沒有任何事情去做材部,因此io_service::run() 將立即返回。
io.run();
和同步方式相比唯竹,它主要有兩點不同:

  • 調(diào)用的是非阻塞函數(shù)async_wait乐导,它的入?yún)⑹且粋€回調(diào)函數(shù)。
  • 顯式調(diào)用io_service.run()函數(shù)驅(qū)動異步IO調(diào)度浸颓。
    值得提出的是物臂,異步回調(diào)函數(shù)handler的參數(shù)中有一個error,注意這個error很重要产上,表明這個handler是因為超時被執(zhí)行還是因為被cancel棵磷。
    符合2種情況之一,handler被執(zhí)行:超時或者被cancel(可以通過此error的值進行區(qū)分)晋涣。
    這同時隱含的說明了除非io.stop被調(diào)用仪媒,否則handler一定會被執(zhí)行。即便是被cancel姻僧。
    被cancel有多種方法规丽,直接調(diào)用cancel或者調(diào)用expires_at蒲牧,expires_from_now重新設置超時時間。

代碼:

#include <iostream>    
#include <boost/asio.hpp>  
#include <boost/thread.hpp>  
#include <boost/date_time/posix_time/posix_time.hpp>  
using namespace std;    
void Print(const boost::system::error_code &ec)  
{  
    cout<<"Hello World!"<<endl;  
    cout<<boost::this_thread::get_id()<<endl;  
}  
int main()  
{    
    cout<<boost::this_thread::get_id()<<endl;  
    boost::asio::io_service io;  
    boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));  
  
    t.async_wait(Print);  
    cout<<"to run"<<endl;  
    io.run();  
    cout<<"exit"<<endl;  
    return 0;    
}

3. 回調(diào)函數(shù)綁定參數(shù)

本例使定時器每秒被激活一次赌莺。例子將示范如何給你的函數(shù)指針傳遞附加參數(shù)冰抢。
使用Asio實現(xiàn)一個重復定時器,你必須在你的回調(diào)函數(shù)中去改變定時器的終止時間艘狭,然后開始一個新的異步等待挎扰。顯然這意味著回調(diào)函數(shù)必須擁有改變定時器對象的權(quán)限。為此我們?yōu)?print函數(shù)增加兩個新參數(shù):

  • 一個指向定時器對象的指針巢音。
  • 一個用于當定時器第6次被激活時我們可以中止程序的計數(shù)器遵倦。
void print(const boost::system::error_code& /*e*/,boost::asio::deadline_timer* t, int* count)

如上所示,示例程序使用了一個計數(shù)器,當定時器被第6次激活時官撼,用來中止程序梧躺。然而,你將看到這里并沒有顯式地要求io_service對象中止傲绣÷痈纾回憶示例2中,當沒有更多“工作”去做時秃诵,io_service::run() 函數(shù)完成续搀。在計數(shù)器達到 5時,定時器并沒有啟動一個新的異步等待菠净。該io_service執(zhí)行完工作后停止運行禁舷。

if (*count < 5)
{
std::cout << *count << "\n";
++(*count);

接著,我們推遲定時器的終止時間毅往。通過在原先的終止時間上增加延時牵咙,我們可以確保定時器不會在處理回調(diào)函數(shù)所需時間內(nèi)到期。

t->expires_at(t->expires_at() + boost::posix_time::seconds(1));

接著我們在定時器中啟動一個新的異步等待煞抬。我們必須使用boost::bind()函數(shù)給你的回調(diào)函數(shù)綁定額外的參數(shù)霜大,因為deadline_timer::async_wait() 函數(shù)只期望得到一個擁用void(const boost::system::error_code&)簽名的函數(shù)指針(或函數(shù)對象)构哺。為你的print函數(shù)綁定附加的參數(shù)后革答,它就成為與簽名精確匹配的函數(shù)對象。
在本例中曙强,boost::bind()的boost::asio::placeholders::error參數(shù)是為了給回調(diào)函數(shù)傳入一個error對象残拐。當開始異步操作時,如果使用boost::bind()碟嘴,你必須指定和回調(diào)函數(shù)的參數(shù)列表相匹配的一個參數(shù)溪食。在示例4中,如果在回調(diào)函數(shù)中娜扇,這個參數(shù)不是必需的错沃,這個占位符會被省略栅组。

t->async_wait(boost::bind(print,
boost::asio::placeholders::error, t, count));
int main()
{
boost::asio::io_service io;

為了在定時器第4次被激活時終止程序,我們添加一個新的count變量枢析。

int count = 0;
boost::asio::deadline_timer t(io,boost::posix_time::seconds(1));

在第四步中玉掸,當在主函數(shù)中的調(diào)用deadline_timer::async_wait() 函數(shù)時,我們綁定print函數(shù)所需要的附加參數(shù)醒叁。

t.async_wait(boost::bind(print,
boost::asio::placeholders::error, &t, &count));
io.run();

最后司浪,為了證明count 變量在print 函數(shù)句柄中被使用,我們打印出它的值把沼。

std::cout << "Final count is " << count << "\n";

代碼

#include <iostream>    
#include <boost/asio.hpp>  
#include <boost/thread.hpp>  
#include <boost/date_time/posix_time/posix_time.hpp>  
using namespace std;    
void Print(const boost::system::error_code &ec,  
            boost::asio::deadline_timer* pt,  
            int * pcount)  
{  
    if (*pcount < 3)  
    {  
        cout<<"count = "<<*pcount<<endl;  
        cout<<boost::this_thread::get_id()<<endl;  
        (*pcount) ++;  
  
        pt->expires_at(pt->expires_at() + boost::posix_time::seconds(5)) ;  
  
        pt->async_wait(boost::bind(Print, boost::asio::placeholders::error, pt, pcount));  
          
    }  
}  
int main()  
{    
    cout<<boost::this_thread::get_id()<<endl;  
    boost::asio::io_service io;  
    boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));  
    int count = 0;  
    t.async_wait(boost::bind(Print, boost::asio::placeholders::error, &t, &count));  
    cout<<"to run"<<endl;  
    io.run();  
    cout << "Final count is " << count << "\n";  
    cout<<"exit"<<endl;  
    return 0;    
}

結(jié)果:

14d0
to run

(等了5s)
count = 0
14d0

(等了5s)
count = 1
14d0

(等了5s)
count = 2
14d0

(等了5s)
Final count is 3
exit

4. 多線程同步回調(diào)

本例示范了使用boost::asio::strand類來創(chuàng)建多線程程序中的同步回調(diào)句柄啊易。

前幾個例程只是在單線程下使用io_service::run() 函數(shù)來避免處理函同步。 如你所見饮睬,Asio庫保證回調(diào)句柄僅能被當前正在調(diào)用 io_service::run(). 函數(shù)的線程調(diào)用租谈。 因此,在單線程中調(diào)用io_service::run() 能確崩Τ睿回調(diào)句柄不被并發(fā)運行垦垂。
下面是Asio在單線程程序中的局限性,尤其是服務器方面牙瓢,包括:

  • 操作需要較長時間處理才能完成時弱響應劫拗。
  • 在大規(guī)模的多處理機系統(tǒng)中表現(xiàn)不佳。

如果你發(fā)現(xiàn)自己陷入這些局限時矾克,一個可供選擇的方法是創(chuàng)建一個每個線程都調(diào)用io_service::run() 的線程池页慷。 不過,因為這允許并發(fā)操作胁附,當訪問一個共享酒繁、非線程安全的資源時,我們需要一個同步方式控妻。
讓我們從定義一個名為printer的類開始州袒,這與前一個示例中的類很相似。這個類是上一個例子的擴展弓候,這里我們使用兩個并行的定時器郎哭。

class CPrinter
{

除了初始化一對boost::asio::deadline_timer 成員變量外,構(gòu)造函數(shù)還初始化一個boost::asio::strand類型strand_ 成員變量菇存。

boost::asio::strand 對象保證:對于通過它來分派執(zhí)行的眾操作中夸研,只有一個操作執(zhí)行完成之后才允許進入下一個操作。 這種保證與多少個線程調(diào)用io_service::run() 無關(guān)依鸥。當然亥至,如果不是通過一個boost::asio::strand對象分派, 或者通過其它不同的boost::asio::strand對象分派,這些操作仍舊可能是并發(fā)的姐扮。

CPrinter(boost::asio::io_service &io)
:m_strand(io)
,m_timer1(io, boost::posix_time::seconds(5))
,m_timer2(io, boost::posix_time::seconds(5))
,m_count(0)
{

當開始同步操作時絮供,每一個回調(diào)句柄都使用boost::asio::strand對象進行“包裝”。strand::wrap()函數(shù)返回一個新的通過boost::asio::strand對象自動分派的內(nèi)部句柄茶敏。 通過同一boost::asio::strand對象對句柄進行“ 包裝”杯缺,我們可以保證操作不會并發(fā)執(zhí)行。

m_timer1.async_wait(m_strand.wrap(boost::bind(&CPrinter::Print1, this) ));
m_timer2.async_wait(m_strand.wrap(boost::bind(&CPrinter::Print2, this) ));
}
~CPrinter()
{
cout<<"m_count = "<<m_count<<endl;
}

在一個多線程程序中睡榆,當訪問同一共享資源時萍肆,異步操作必須是同步的。在本例中胀屿,print1 和print2)函數(shù)使用的共享資源std::cout 和count_數(shù)據(jù)成員塘揣。

void Print1()
{
if (m_count < 10)
{
cout<<"Timer1 count = "<<m_count<<endl;
cout<<boost::this_thread::get_id()<<endl;
m_count++;
m_timer1.expires_at(m_timer1.expires_at() + boost::posix_time::seconds(1)) ;
m_timer1.async_wait(m_strand.wrap(boost::bind(&CPrinter::Print1, this) ) );
}
}
void Print2()
{
if (m_count < 10)
{
cout<<"Timer2 count = "<<m_count<<endl;
cout<<boost::this_thread::get_id()<<endl;
m_count++;
m_timer2.expires_at(m_timer2.expires_at() + boost::posix_time::seconds(1)) ;
m_timer2.async_wait(m_strand.wrap(boost::bind(&CPrinter::Print2, this) ) );
}
}
private:
boost::asio::strand m_strand;
boost::asio::deadline_timer m_timer1;
boost::asio::deadline_timer m_timer2;
int m_count;

};

main函數(shù)中,io_service::run()現(xiàn)在被兩個線程調(diào)用:主線程和一個附加線程宿崭。這一切依賴于boost::thread對象來完成亲铡。
正如它被一個單線程調(diào)用一樣,io_service::run()的并發(fā)調(diào)用會一直持續(xù)到無任何“工作”可做葡兑。后臺線程直到所有異步操作都完成后才會退出奖蔓。

int main()
{ 
cout<<boost::this_thread::get_id()<<endl;
boost::asio::io_service io;
CPrinter cp(io);

cout<<"to run"<<endl;

boost::thread td(boost::bind(&boost::asio::io_service::run, &io));

io.run();

cout<<"exit"<<endl;
return 0; 
}

代碼

#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/thread.hpp>

boost::asio::io_service Service;

class Timer
{
private:
    boost::asio::deadline_timer timer1;
    boost::asio::deadline_timer timer2;
    boost::asio::strand m_strand;
    int count;

public:
    Timer(boost::asio::io_service& ref_service)
        :timer1(ref_service, boost::posix_time::seconds(3))
        , timer2(ref_service, boost::posix_time::seconds(3))
        , m_strand(ref_service)
        , count(0)
    {

        timer1.async_wait(m_strand.wrap(boost::bind(&Timer::Print1, this, boost::asio::placeholders::error)));
        timer2.async_wait(m_strand.wrap(boost::bind(&Timer::Print2, this, boost::asio::placeholders::error)));

    }
    ~Timer()
    {

    }
    void Print1(const boost::system::system_error& error)
    {
        if (count < 5)
        {
            std::cout << "Pints1's count:" << count<<std::endl;
            std::cout << boost::this_thread::get_id() <<std:: endl;
            ++count;
            timer1.expires_at(timer1.expires_at() + boost::posix_time::seconds(1));
            timer1.async_wait(m_strand.wrap(boost::bind(&Timer::Print1, this, boost::asio::placeholders::error)));
        }
        else
        {
            std::cout << "the Error is:" << error.what() << std::endl;
        }
    }

    void Print2(const boost::system::system_error& error)
    {
        if (count < 5)
        {
            std::cout << "Print2's count :" <<count<< std::endl;
            std::cout << boost::this_thread::get_id() << std::endl;
            ++count;
            timer2.expires_at(timer2.expires_at() + boost::posix_time::seconds(1));
            timer2.async_wait(m_strand.wrap(boost::bind(&Timer::Print2, this, boost::asio::placeholders::error)));
        }
        else
        {
            std::cout << "the Error is:" << error.what() << std::endl;
            boost::asio::io_service::work work(Service);
        }
    }

};

int main(int argc, char** argv)
{
    
    std::cout << boost::this_thread::get_id() << std::endl;
    Timer m_timer(Service);


    std::cout << "異步給主線程運行到io_Service::run之前,知道異步回調(diào)函數(shù)調(diào)完" << std::endl;
    boost::thread t([&](){ std::cout << "\n進入t線程內(nèi)部執(zhí)行" << boost::this_thread::get_id() << std::endl;; Service.run();
                        std::cout << "t線程內(nèi)部:異步給主線程運行到io_Service::run之前讹堤,知道異步回調(diào)函數(shù)調(diào)完    (驗證)吆鹤!" << std::endl; });
    t.detach();

    std::cout << "異步給主線程運行到io_Service::run之前,知道異步回調(diào)函數(shù)調(diào)完" << std::endl;
    Service.run();
    std::cout << "異步給主線程運行到io_Service::run之前洲守,知道異步回調(diào)函數(shù)調(diào)完    (驗證)疑务!" << std::endl;
    getchar();
    return 0;
}

運行結(jié)果:

2544
異步給主線程運行到io_Service::run之前,知道異步回調(diào)函數(shù)調(diào)完
異步給主線程運行到io_Service::run之前梗醇,知道異步回調(diào)函數(shù)調(diào)完
進入t線程內(nèi)部執(zhí)行23d4

Print2's count :0
23d4
Pints1's count:1
2544
Pints1's count:2
2544
Print2's count :3
23d4
Print2's count :4
23d4
the Error is:操作成功完成知允。
the Error is:操作成功完成。
異步給主線程運行到io_Service::run之前叙谨,知道異步回調(diào)函數(shù)調(diào)完    (驗證)温鸽!
t線程內(nèi)部:異步給主線程運行到io_Service::run之前,知道異步回調(diào)函數(shù)調(diào)完    (驗證)手负!

說明:

  • 兩個Timer確實是在不同線程中執(zhí)行涤垫,并且只有一個print操作執(zhí)行完成之后才允許進入另一個print操作

  • Timer1始終在一個線程中執(zhí)行,Timer2始終在另一個線程中執(zhí)行虫溜,(但不一定就是Timer1在主線程執(zhí)行雹姊,這個分配時隨機的)
    注意:
    deadline_timer和socket一樣,都用io_service作為構(gòu)造函數(shù)的參數(shù)衡楞。在其上進行異步操作,都將導致和io_service所包含的iocp相關(guān)聯(lián)。這同樣意味著在析構(gòu) io_service之前瘾境,必須析構(gòu)關(guān)聯(lián)在這個io_service上的deadline_timer歧杏。
    引申:
    關(guān)于boost::asio::strand,有三個函數(shù):post, dispatch, wrap
    post: 不管什么情況都會把任務丟到隊列中迷守,然后立即返回犬绒。如:m_strand.post(boost::bind(print, 2));
    dispatch: 如果跟run()在一個線程,那么任務會直接在dispatch內(nèi)部調(diào)用兑凿,執(zhí)行結(jié)束后返回凯力。不在一個線程跟post一樣。如:m_strand.dispatch(boost::bind(print, 1));

wrap:返回一個新的通過boost::asio::strand對象自動分派的內(nèi)部句柄
注意事項:
異步等待時礼华,程序會先執(zhí)行主線程需要執(zhí)行的操作咐鹤,直到io_service::run之前的語句;當回調(diào)函數(shù)都執(zhí)行完成之后圣絮,才繼續(xù)執(zhí)行io_service::run之后的操作祈惶,

有時你如果沒給io_service::run做點事,run會立馬返回扮匠,導致程序無響應捧请,解決辦法是添加boost::asio::io_service::work work(io_Service), work對象不析構(gòu),run是不會立即返回的棒搜!

work轉(zhuǎn)載來自:http://blog.csdn.net/huang_xw/article/details/8471057
其中異步調(diào)用時疹蛉,用boost::asio::strand,strand.wrap(boost::bind(....)),為了在函數(shù)共享數(shù)據(jù)時,使函數(shù)一縷一縷的執(zhí)行力麸,strand會內(nèi)部打包函數(shù)氧吐,返回自己隨機分配函數(shù)句炳!

還有末盔,異步等待的時間要夠回調(diào)函數(shù)的執(zhí)行時間筑舅,否則會直接調(diào)用異步等待,所以你可以加入延時函數(shù)陨舱,deadline_timer::expires_at(.expires.at()+boost::posix_time::senconds(5));保證回調(diào)函數(shù)的執(zhí)行時間翠拣;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市游盲,隨后出現(xiàn)的幾起案子误墓,更是在濱河造成了極大的恐慌,老刑警劉巖益缎,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谜慌,死亡現(xiàn)場離奇詭異,居然都是意外死亡莺奔,警方通過查閱死者的電腦和手機欣范,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人恼琼,你說我怎么就攤上這事妨蛹。” “怎么了晴竞?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵蛙卤,是天一觀的道長。 經(jīng)常有香客問我噩死,道長颤难,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任已维,我火速辦了婚禮行嗤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘衣摩。我一直安慰自己昂验,他們只是感情好,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布艾扮。 她就那樣靜靜地躺著既琴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪泡嘴。 梳的紋絲不亂的頭發(fā)上甫恩,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機與錄音酌予,去河邊找鬼磺箕。 笑死,一個胖子當著我的面吹牛抛虫,可吹牛的內(nèi)容都是我干的松靡。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼建椰,長吁一口氣:“原來是場噩夢啊……” “哼雕欺!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起棉姐,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤屠列,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后伞矩,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體笛洛,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年乃坤,在試婚紗的時候發(fā)現(xiàn)自己被綠了苛让。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片沟蔑。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蝌诡,靈堂內(nèi)的尸體忽然破棺而出溉贿,到底是詐尸還是另有隱情枫吧,我是刑警寧澤浦旱,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站九杂,受9級特大地震影響颁湖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜例隆,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一甥捺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧镀层,春花似錦镰禾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至坞古,卻和暖如春备韧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背痪枫。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工织堂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人奶陈。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓易阳,卻偏偏與公主長得像,于是被迫代替她去往敵國和親吃粒。 傳聞我的和親對象是個殘疾皇子潦俺,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 1 簡介 Boost.Asio和Libuv都是非常優(yōu)秀的網(wǎng)絡通訊框架。本文使用兩種技術(shù)声搁,在CentOS上各自實現(xiàn)一...
    Brent姜閱讀 9,195評論 0 10
  • Most programs interact with the outside world in some way...
    toMyLord閱讀 1,706評論 0 1
  • 1.2.3 線程和Asio 線程安全一般來說黑竞,并發(fā)使用不同的對象是安全的,使用單個對象是不安全的疏旨。 但是很魂,像io_...
    山羊歌的演唱會閱讀 1,200評論 0 1
  • 我對boost.asio的使用不深入,所以總是過了一段時間就會對它的理解上又變得模糊起來檐涝。還是先回頭看看boost...
    Brent姜閱讀 1,091評論 0 0
  • 保爾意識到陌生人那雙安詳?shù)幕已劬φ趯徱曀舸摇D菆远ǖ姆òぁ⒛⒌哪孔尡柛械骄狡取_@個陌生人穿著一件灰色短褂幅聘,自...
    佳音0911閱讀 1,267評論 0 0