亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

蟲蟲首頁| 資源下載| 資源專輯| 精品軟件
登錄| 注冊

您現在的位置是:首頁 > 技術閱讀 >  C++ 使用協程需要注意的問題

C++ 使用協程需要注意的問題

時間:2024-02-15


在異步操作里,如異步連接、異步讀寫之類的協程,co_await這些協程時需要注意線程切換的細節。

以asio異步連接協程為例:

class client {
public:
    client() {
        thd_ = std::thread([this]{
            io_ctx_.run();
        });
    }

    async_simple::coro::Lazy<bool> async_connect(auto host, auto port) {
        bool ret = co_await util::async_connect(host, port);  #1
        co_return ret;      #2                                 
    }

    ~client() {
        io_ctx_.stop();
        if(thd_.joinable()) {
            thd_.join();
        }
    }

private:
  asio::io_context io_ctx_;
  std::thread thd_;
};

int main() {
    client c;
    async_simple::coro::syncAwait(c.async_connect());
    std::cout<<"quit\n"#3
}

這個例子很簡單,client在連接之后就析構了,看起來沒什么問題。但是運行之后就會發生線程join的錯誤,錯誤的意思是在線程里join自己了。這是怎么回事?co_await一個異步連接的協程,當連接成功后協程返回,這時候發生了線程切換。異步連接返回的時候是在io_context的線程里,代碼中的#1在主線程,#2在io_context線程,之后就co_return 返回到main函數的#3,這時候#3仍然在io_context線程里,接著client就會析構了,這時候仍然在io_context線程里,析構的時候會調用thd_.join(); 然后就導致了在io_context的線程里join自己的錯誤。

這是使用協程時容易犯錯的一個地方,解決方法就是避免co_await回來之后去析構client,或者co_await回來仍然回到主線程。這里可以考慮用協程條件變量,在異步連接的時候發起一個新的協程并傳入協程條件變量并在連接返回后set_value,主線程去co_await這個條件變量,這樣連接返回后就回到主線程了,就可以解決在io線程里join自己的問題了。

還是以上面的異步連接為例子,需要對之前的async_connect協程增加一個超時功能,代碼稍作修改:

class client {
public:
    client() : socket_(io_ctx_) {
        thd_ = std::thread([this]{
            io_ctx_.run();
        });
    }

    async_simple::coro::Lazy<bool> async_connect(auto host, auto port, auto duration) {
        coro_timer timer(io_ctx_);
        timeout(timer, duration).start([](auto&&){}); // #1 啟動一個新協程做超時處理
        bool ret = co_await util::async_connect(host, port, socket_);//假設這里co_await返回后回到主線程
        co_return ret;                                      
    }

    ~client() {
        io_ctx_.stop();
        if(thd_.joinable()) {
            thd_.join();
        }
    }


private:
  async_simple::coro::Lazy<void> timeout(auto &timer, auto duration) {
    bool is_timeout = co_await timer.async_wait(duration);
    if(is_timeout) {
        asio::error_code ignored_ec;
        socket_.shutdown(tcp::socket::shutdown_both, ignored_ec);
        socket_.close(ignored_ec);
    }

    co_return;
  }

  asio::io_context io_ctx_;
  tcp::socket socket_;
  std::thread thd_;
  bool is_timeout_;
};

int main() {
    client c;
    async_simple::coro::syncAwait(c.async_connect("localhost""9000", 5s));
    std::cout<<"quit\n"#3
}

這個代碼增加連接超時處理的協程,注意#1那里為什么需要新啟動一個協程,而不能用co_await呢?因為co_await是阻塞語義,co_await會導致永遠超時,啟動一個新的協程不會阻塞當前協程從而可以去調用async_connect。

當timeout超時發生時就關閉socket,這時候async_connect就會返回錯誤然后返回到調用者,這看起來似乎可以對異步連接做超時處理了,但是這個代碼是有問題的。假如異步連接沒有超時會發生什么?沒有超時的話就返回到main函數了,然后client就析構了,當timeout協程resume回來的時候client其實已經析構了,這時候再去調用成員變量socket_ close將會導致一個訪問已經析構對象的錯誤。

也許有人會說,那就在co_return之前去取消timer不就好了嗎?這個辦法也不行,因為取消timer,timeout協程并不會立即返回,仍然會存在訪問已經析構對象的問題。

正確的做法應該是對兩個協程進行同步,timeout協程和async_connect協程需要同步,在async_connect協程返回之前需要確保timeout協程已經完成,這樣就可以避免訪問已經析構對象的問題了。

這個問題其實也是異步回調安全返回的一個經典問題,協程也同樣會遇到這個問題,上面提到的對兩個協程進行同步是解決方法之一,另外一個方法就是使用shared_from_this,就像異步安全回調那樣處理。

還是以異步連接為例:

async_simple::coro::Lazy<bool> async_connect(const std::string &host, const std::string& port) {
    co_return co_await util::async_connect(host, port);
}

async_simple::coro::Lazy<void> test_connect() {
    bool ok = co_await async_connect("localhost""8000");
    if(!ok){
        std::cout<<"connect failed\n";
    }

    std::cout<<"connect ok\n";
}

int main() {
    async_simple::coro::syncAwait(test_connect());
}

這個代碼簡單明了,就是測試一下異步連接是否成功,運行也是正常的。如果稍微改一下test_connect:

async_simple::coro::Lazy<void> test_connect() {
    auto lazy = async_connect("localhost""8000");
    bool ok = co_await lazy;
    if(!ok){
        std::cout<<"connect failed\n";
    }

    std::cout<<"connect ok\n";
}

很遺憾,這個代碼會導致連接總是失敗,似乎很奇怪,后面發現原因是因為async_connect的兩個參數失效了,但是寫法和剛開始的寫法幾乎一樣,為啥后面這種寫法會導致參數失效呢?

原因是co_await一個協程函數時,其實做了兩件事:

  • 調用協程函數創建協程,這個步驟會創建協程幀,把參數和局部變量拷貝到協程幀里;

  • co_await執行協程函數;

回過頭來看auto lazy = async_connect("localhost", "8000"); 這個代碼調用協程函數創建了協程,這時候拷貝到協程幀里面的是兩個臨時變量,在這一行結束的時候臨時變量就析構了,在下一行去co_await執行這個協程的時候就會出現參數失效的問題了。

co_await async_connect("localhost", "8000"); 這樣為什么沒問題呢,因為協程創建和協程調用都在一行完成的,臨時變量知道協程執行之后才會失效,因此不會有問題。

問題的本質其實是C++臨時變量生命周期的問題。使用協程的時候稍微注意一下就好了,可以把const std::string&改成std::string,這樣就不會臨時變量生命周期的問題了,如果不想改參數類型就co_await 協程函數就好了,不分成兩行去執行協程。

文章轉載自:www.purecpp.cn

亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
久久精品麻豆| 国产精品青草久久久久福利99| 美女主播一区| 欧美日韩成人一区二区三区| 亚洲精品免费一二三区| 久久精品国产精品| 欧美精品18+| 欧美一区二区三区四区夜夜大片 | 99国内精品久久| 久久久久一区二区三区| 影音先锋亚洲精品| 亚洲一区二三| 亚洲精品日韩在线观看| 欧美成人精品福利| 国产一区三区三区| 久久午夜电影网| 亚洲视频久久| 国产精品免费看| 日韩小视频在线观看专区| 国产精品成人观看视频免费| 亚洲毛片在线观看| 久久爱另类一区二区小说| 国产女精品视频网站免费 | 亚洲视频播放| 欧美日韩久久不卡| 99riav国产精品| 国产精品第一页第二页第三页| 欧美高清在线一区| 国产一区二区三区最好精华液| 久久久久国色av免费看影院| 一本久久综合| 国产一区再线| 国产精品一区二区三区久久| 久久不射2019中文字幕| 亚洲素人一区二区| 国产视频精品免费播放| 欧美在线日韩精品| 一区二区三区精密机械公司 | 亚洲人人精品| 久热这里只精品99re8久| 亚洲一级二级在线| 亚洲一区久久久| 亚洲激情在线视频| 国产亚洲日本欧美韩国| 欧美精品大片| 国产一区二区久久精品| 国产精品免费视频观看| 欧美精品一区二区三区在线看午夜| 夜夜爽夜夜爽精品视频| 欧美日韩国产va另类| 国产精品久久久久久久浪潮网站| 免费国产自线拍一欧美视频| 久久精品2019中文字幕| 日韩视频在线一区二区三区| 欧美午夜激情视频| 极品尤物av久久免费看| 狠狠狠色丁香婷婷综合激情| 国产精品v亚洲精品v日韩精品| 欧美日韩一区二区三区高清| 欧美精品一区二区三区在线播放 | 欧美精品久久99| 欧美xxx成人| 欧美精品一区二区在线播放| 欧美视频在线观看| 国产精品xvideos88| 久久精品官网| 欧美日韩在线一二三| 欧美黄色一级视频| 国产精品一二三| 在线观看一区二区视频| 一区二区欧美视频| 欧美一区二区| 欧美精品一区二区三区蜜桃 | 亚洲精品久久久一区二区三区| 亚洲最黄网站| 亚洲视频久久| 快射av在线播放一区| 欧美激情一区二区三级高清视频| 国产精品v一区二区三区| 欧美三日本三级少妇三2023| 欧美日韩成人一区二区| 亚洲欧美精品在线观看| 好吊日精品视频| 久久久综合网| 在线视频一区二区| 香蕉视频成人在线观看| 国产精品一区二区黑丝| 亚洲国产精品久久人人爱蜜臀| 亚洲视频一区二区在线观看| 欧美另类专区| 一区二区三区在线观看欧美| 欧美一级欧美一级在线播放| 国产在线精品自拍| 国产精品国色综合久久| 好吊一区二区三区| 国产精品va在线| 亚洲国产导航| 欧美极品在线观看| 久久久精品tv| 午夜亚洲性色福利视频| 亚洲欧洲久久| 亚洲高清不卡在线| 国产精品日韩精品欧美精品| 久久成人亚洲| 欧美一区91| 欧美一区日本一区韩国一区| 91久久线看在观草草青青| 欧美午夜欧美| 欧美日韩成人综合在线一区二区 | 久久免费精品视频| 亚洲你懂的在线视频| 亚洲精品女人| 99热精品在线观看| av成人免费在线观看| 99re亚洲国产精品| 99视频在线精品国自产拍免费观看 | 免费亚洲婷婷| 欧美日韩精品欧美日韩精品一| 欧美顶级大胆免费视频| 久久综合九九| 欧美激情区在线播放| 欧美日韩在线免费观看| 国产拍揄自揄精品视频麻豆| 国产农村妇女精品一二区| 国产精品久久波多野结衣| 在线观看视频日韩| 久久夜精品va视频免费观看| 国产精品香蕉在线观看| 亚洲在线播放| 免费亚洲一区二区| 亚洲欧洲在线播放| 欧美成人视屏| 亚洲美女av在线播放| 欧美日韩亚洲一区三区| 亚洲视频在线二区| 欧美日韩人人澡狠狠躁视频| 久久精品国产欧美激情| 亚洲欧美日韩在线高清直播| 久久久噜噜噜久久中文字幕色伊伊 | 在线中文字幕一区| 美女性感视频久久久| 韩国av一区二区三区| 久久成人在线| 国产区精品视频| 欧美一区二区三区的| 国产欧美日本一区二区三区| av成人黄色| 欧美视频在线观看免费| 亚洲精品日韩激情在线电影| 久久久久久久久蜜桃| 国产主播在线一区| 亚洲一区二区在线| 欧美一区深夜视频| 久久精品国产精品 | 国产亚洲欧美日韩精品| 欧美色视频日本高清在线观看| 久久免费视频一区| 香蕉久久精品日日躁夜夜躁| 亚洲综合国产激情另类一区| 久久精品水蜜桃av综合天堂| 欧美成人国产va精品日本一级| 欧美成人免费全部观看天天性色| 久久伊人免费视频| 欧美粗暴jizz性欧美20| 伊人久久综合97精品| 亚洲大胆女人| 中文精品视频一区二区在线观看| 欧美aa在线视频| 在线天堂一区av电影| 国产精品每日更新| 久久久xxx| 正在播放日韩| 亚洲经典一区| 国产精品久久国产愉拍| 欧美成人综合一区| 久久精品亚洲国产奇米99| 亚洲欧洲在线看| 狠狠久久五月精品中文字幕| 欧美日韩亚洲一区二区三区四区| 久久久综合香蕉尹人综合网| 亚洲欧美不卡| 亚洲一区三区视频在线观看| 亚洲精品久久久久久久久久久| 国产一区二区观看| 国模吧视频一区| 国产亚洲欧洲| 海角社区69精品视频| 国产亚洲一区二区精品| 国产老肥熟一区二区三区| 欧美日韩亚洲高清| 国产精品高精视频免费| 国产精品国产三级国产专播品爱网 | 久久国产日本精品| 久久精品欧洲| 欧美成人免费va影院高清| 欧美电影打屁股sp| 国产精品久久久久9999吃药| 国产精品视频免费观看| 曰韩精品一区二区| 一本久道久久综合狠狠爱|