色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

co_await這些協程時需要注意線程切換的細節

程序喵大人 ? 來源:程序喵大人 ? 作者:程序喵大人 ? 2022-11-03 09:18 ? 次閱讀

bfc58fd8-5b13-11ed-a3b6-dac502259ad0.png

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

以asio異步連接協程為例:

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

async_simple::Lazyasync_connect(autohost,autoport){
boolret=co_awaitutil::async_connect(host,port);#1
co_returnret;#2
}

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

private:
asio::io_contextio_ctx_;
std::threadthd_;
};

intmain(){
clientc;
async_simple::syncAwait(c.async_connect());
std::cout<<"quit
";#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自己的問題了。

bfc58fd8-5b13-11ed-a3b6-dac502259ad0.png

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

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

async_simple::Lazyasync_connect(autohost,autoport,autoduration){
coro_timertimer(io_ctx_);
timeout(timer,duration).start([](auto&&){});//#1啟動一個新協程做超時處理
boolret=co_awaitutil::async_connect(host,port,socket_);//假設這里co_await返回后回到主線程
co_returnret;
}

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


private:
async_simple::Lazytimeout(auto&timer,autoduration){
boolis_timeout=co_awaittimer.async_wait(duration);
if(is_timeout){
asio::error_codeignored_ec;
socket_.shutdown(tcp::shutdown_both,ignored_ec);
socket_.close(ignored_ec);
}

co_return;
}

asio::io_contextio_ctx_;
tcp::socketsocket_;
std::threadthd_;
boolis_timeout_;
};

intmain(){
clientc;
async_simple::syncAwait(c.async_connect("localhost","9000",5s));
std::cout<<"quit
";#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::Lazyasync_connect(conststd::string&host,conststd::string&port){
co_returnco_awaitutil::async_connect(host,port);
}

async_simple::Lazytest_connect(){
boolok=co_awaitasync_connect("localhost","8000");
if(!ok){
std::cout<<"connectfailed
";
}

std::cout<<"connectok
";
}

intmain(){
async_simple::syncAwait(test_connect());
}

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

async_simple::Lazytest_connect(){
autolazy=async_connect("localhost","8000");
boolok=co_awaitlazy;
if(!ok){
std::cout<<"connectfailed
";
}

std::cout<<"connectok
";
}

很遺憾,這個代碼會導致連接總是失敗,似乎很奇怪,后面發現原因是因為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 協程函數就好了,不分成兩行去執行協程。

審核編輯 :李倩


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 變量
    +關注

    關注

    0

    文章

    613

    瀏覽量

    28413
  • 線程
    +關注

    關注

    0

    文章

    505

    瀏覽量

    19709

原文標題:C++ 使用協程需要注意的問題

文章出處:【微信號:程序喵大人,微信公眾號:程序喵大人】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    RAKsmart服務器升級需要注意哪些細節

    RAKsmart是一家知名的IDC(互聯網數據中心)服務提供商,為廣大用戶提供包括服務器托管、租用在內的多種服務。當您的業務需求發生變化或者技術進步導致現有配置不再滿足要求時,對服務器進行升級就顯得尤為重要。以下是進行RAKsmart服務器升級時需要注意的一些關鍵細節
    的頭像 發表于 09-25 09:56 ?209次閱讀

    暢玩《黑神話:悟空》,除了“官配”硬件還需要注意這些......

    暢玩《黑神話:悟空》,除了“官配”硬件還需要注意這些......
    的頭像 發表于 08-30 14:58 ?476次閱讀
    暢玩《黑神話:悟空》,除了“官配”硬件還<b class='flag-5'>需要注意</b><b class='flag-5'>這些</b>......

    bnc公頭注塑需要注意什么

    德索工程師說道在BNC公頭注塑過程中,需要注意多個方面以確保產品的質量和生產效率。以下是對這一過程中關鍵注意事項的詳細闡述:   材料選擇:根據BNC公頭的使用環境和性能要求,選擇合適的注塑
    的頭像 發表于 08-22 08:53 ?261次閱讀
    bnc公頭注塑<b class='flag-5'>需要注意</b>什么

    共模電感選型參數需要注意哪些

    電子發燒友網站提供《共模電感選型參數需要注意哪些.docx》資料免費下載
    發表于 07-30 14:23 ?0次下載

    IR615S橋接AP,在相同SSID的AP間不能切換,需要注意哪些設置呢?

    現場有多個AP,用相同的SSID,沒有使用AC,現場IR615S WiFi橋接AP WiFi時,當連接的AP關閉后,不能切換到到其他AP上,需要注意哪些設置?
    發表于 07-25 06:38

    FPGA實現SDIO訪問需要注意的問題

    FPGA實現SDIO訪問時,需要注意以下幾個關鍵問題和細節: 初始化過程: SDIO總線的初始化是確保FPGA與SD卡能夠正常通信的第一步。這包括設置時鐘頻率、配置數據傳輸模式以及校驗協議等
    發表于 06-27 08:38

    應用PLC需要注意哪些問題

    PLC(可編程邏輯控制器)作為現代工業控制的核心設備,其應用的廣泛性和重要性不言而喻。然而,在應用PLC的過程中,也需要注意一系列問題,以確保PLC系統的穩定運行和高效控制。本文將結合實際應用經驗,詳細探討應用PLC時需要注意的問題,并給出相應的解決策略和建議。
    的頭像 發表于 06-17 11:29 ?599次閱讀

    FPGA的sata接口設計時需要注意哪些問題

    在FPGA的SATA接口設計時,需要注意以下幾個方面的問題,以確保設計的穩定性和性能: 接口版本和速度 : SATA有三代標準,分別為SATA I(1.5 Gb/s)、SATA II(3.0 Gb
    發表于 05-27 16:20

    pcb電路板元件布局需要注意什么

    pcb電路板元件布局需要注意什么
    的頭像 發表于 03-14 15:24 ?911次閱讀

    鴻蒙原生應用開發-ArkTS語言基礎類庫異步并發簡述async/await

    Promise對象的解析,并將其解析值存儲在result變量中。 需要注意的是,由于要等待異步操作完成,因此需要將整個操作包在async函數中。除了在async函數中使用await外,還可以使用try/catch
    發表于 03-06 14:44

    激光焊接技術在焊接鋁合金時需要注意什么

    需要填充材料,減少了材料成本和加工時間。下面來看看激光焊接技術在焊接鋁合金時需要注意什么。 在激光焊接鋁合金時需要注意以下幾點: 1.清理焊縫表面:在焊接前,需要將焊縫表面的油污、氧
    的頭像 發表于 02-29 13:43 ?891次閱讀
    激光焊接技術在焊接鋁合金時<b class='flag-5'>需要注意</b>什么

    智能手環設計需要注意哪些

    隨著電子技術的高速發展,可穿戴設備逐漸火爆,其中之一是智能手環,作為現代可穿戴技術的熱門產品之一,它集成了多種功能,如健康檢測、運動跟蹤、通知提醒等,為了實現這些功能,需要用上哪些電路模塊,在設計時需要注意哪些?下面一起來看看吧
    的頭像 發表于 02-25 09:34 ?986次閱讀

    讓激光位移傳感器更精準,安裝的時候需要注意這些細節

    和應用上也擁有豐富的經驗。本期小明就來盤點一下,激光位移傳感器在安裝的時候根據被測物及環境需要注意的關鍵點?!嗝髦尉芗す馕灰苽鞲衅髻Y料點擊圖片獲取1材料/顏色存在
    的頭像 發表于 02-19 12:48 ?1211次閱讀
    讓激光位移傳感器更精準,安裝的時候<b class='flag-5'>需要注意</b><b class='flag-5'>這些</b><b class='flag-5'>細節</b>

    使用電容降壓時都需要注意哪些?

    使用電容降壓時都需要注意哪些? 電容降壓是一種常見且廣泛應用的電路降壓方式,它可以將高電壓降低至設定的較低電壓,并且具有穩定、簡便、高效、可靠等優點。然而,在使用電容降壓時,我們需要注意一些關鍵
    的頭像 發表于 02-02 15:27 ?607次閱讀

    談談的那些事兒

    隨著異步編程的發展以及各種并發框架的普及,作為一種異步編程規范在各類語言中地位逐步提高。我們不單單會在自己的程序中使用,各類框架如fastapi,aiohttp等也都是基于異步
    的頭像 發表于 01-26 11:36 ?1124次閱讀
    談談<b class='flag-5'>協</b><b class='flag-5'>程</b>的那些事兒
    主站蜘蛛池模板: 7723手机游戏破解版下载| 2021国产精品视频| 日本免费一区二区三区最新vr| 欧美狂野乱码一二三四区| 母乳女神春日もな| 欧美一区二区视频97色伦| 欧美一区二区日韩一区二区| 日日噜噜噜夜夜爽爽狠狠| 色妺妺免费影院| 香蕉免费高清完整| 妖精视频免费看| 91区国产福利在线观看午夜| CHINESE熟女老女人HD视频| jj插入bb| 国产精品嫩草影院一区二区三区| 国产欧美一区二区三区视频 | 24小时日本在线观看片| 97在线精品视频免费| 被窝国产理论一二三影院| 国产福利视频一区二区| 精品国产乱码久久久久久人妻 | 伊人久久综在合线亚洲| 9久爱午夜视频| 国产精品永久在线| 蜜桃传媒一区二区亚洲AV| 色狗av影院| 中文无码熟妇人妻AV在线| 高清国产mv视频在线观看| 久久国产精品久久国产精品| 日本后进式猛烈xx00动态图| 亚洲精品视频免费观看| jyzzjyzzz视频国产在线观看| 国产在线观看成人免费视频| 男人就爱吃这套下载| 性色AV一区二区三区V视界影院| 52色擼99热99| 激情女人花| 玩弄朋友娇妻呻吟交换电影 | 欧美特级特黄a大片免费| 亚洲黄色免费观看| 成人国产精品日本在线|