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

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

co_await這些協(xié)程時(shí)需要注意線程切換的細(xì)節(jié)

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

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

在異步操作里,如異步連接、異步讀寫(xiě)之類的協(xié)程,co_await這些協(xié)程時(shí)需要注意線程切換的細(xì)節(jié)。

以asio異步連接協(xié)程為例:

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
}

這個(gè)例子很簡(jiǎn)單,client在連接之后就析構(gòu)了,看起來(lái)沒(méi)什么問(wèn)題。但是運(yùn)行之后就會(huì)發(fā)生線程join的錯(cuò)誤,錯(cuò)誤的意思是在線程里join自己了。這是怎么回事?co_await一個(gè)異步連接的協(xié)程,當(dāng)連接成功后協(xié)程返回,這時(shí)候發(fā)生了線程切換。異步連接返回的時(shí)候是在io_context的線程里,代碼中的#1在主線程,#2在io_context線程,之后就co_return 返回到main函數(shù)的#3,這時(shí)候#3仍然在io_context線程里,接著client就會(huì)析構(gòu)了,這時(shí)候仍然在io_context線程里,析構(gòu)的時(shí)候會(huì)調(diào)用thd_.join(); 然后就導(dǎo)致了在io_context的線程里join自己的錯(cuò)誤。

這是使用協(xié)程時(shí)容易犯錯(cuò)的一個(gè)地方,解決方法就是避免co_await回來(lái)之后去析構(gòu)client,或者co_await回來(lái)仍然回到主線程。這里可以考慮用協(xié)程條件變量,在異步連接的時(shí)候發(fā)起一個(gè)新的協(xié)程并傳入?yún)f(xié)程條件變量并在連接返回后set_value,主線程去co_await這個(gè)條件變量,這樣連接返回后就回到主線程了,就可以解決在io線程里join自己的問(wèn)題了。

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

還是以上面的異步連接為例子,需要對(duì)之前的async_connect協(xié)程增加一個(gè)超時(shí)功能,代碼稍作修改:

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啟動(dòng)一個(gè)新協(xié)程做超時(shí)處理
boolret=co_awaitutil::async_connect(host,port,socket_);//假設(shè)這里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
}

這個(gè)代碼增加連接超時(shí)處理的協(xié)程,注意#1那里為什么需要新啟動(dòng)一個(gè)協(xié)程,而不能用co_await呢?因?yàn)閏o_await是阻塞語(yǔ)義,co_await會(huì)導(dǎo)致永遠(yuǎn)超時(shí),啟動(dòng)一個(gè)新的協(xié)程不會(huì)阻塞當(dāng)前協(xié)程從而可以去調(diào)用async_connect。

當(dāng)timeout超時(shí)發(fā)生時(shí)就關(guān)閉socket,這時(shí)候async_connect就會(huì)返回錯(cuò)誤然后返回到調(diào)用者,這看起來(lái)似乎可以對(duì)異步連接做超時(shí)處理了,但是這個(gè)代碼是有問(wèn)題的。假如異步連接沒(méi)有超時(shí)會(huì)發(fā)生什么?沒(méi)有超時(shí)的話就返回到main函數(shù)了,然后client就析構(gòu)了,當(dāng)timeout協(xié)程resume回來(lái)的時(shí)候client其實(shí)已經(jīng)析構(gòu)了,這時(shí)候再去調(diào)用成員變量socket_ close將會(huì)導(dǎo)致一個(gè)訪問(wèn)已經(jīng)析構(gòu)對(duì)象的錯(cuò)誤。

也許有人會(huì)說(shuō),那就在co_return之前去取消timer不就好了嗎?這個(gè)辦法也不行,因?yàn)槿∠鹴imer,timeout協(xié)程并不會(huì)立即返回,仍然會(huì)存在訪問(wèn)已經(jīng)析構(gòu)對(duì)象的問(wèn)題。

正確的做法應(yīng)該是對(duì)兩個(gè)協(xié)程進(jìn)行同步,timeout協(xié)程和async_connect協(xié)程需要同步,在async_connect協(xié)程返回之前需要確保timeout協(xié)程已經(jīng)完成,這樣就可以避免訪問(wèn)已經(jīng)析構(gòu)對(duì)象的問(wèn)題了。

這個(gè)問(wèn)題其實(shí)也是異步回調(diào)安全返回的一個(gè)經(jīng)典問(wèn)題,協(xié)程也同樣會(huì)遇到這個(gè)問(wèn)題,上面提到的對(duì)兩個(gè)協(xié)程進(jìn)行同步是解決方法之一,另外一個(gè)方法就是使用shared_from_this,就像異步安全回調(diào)那樣處理。

還是以異步連接為例:

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());
}

這個(gè)代碼簡(jiǎn)單明了,就是測(cè)試一下異步連接是否成功,運(yùn)行也是正常的。如果稍微改一下test_connect:

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

std::cout<<"connectok
";
}

很遺憾,這個(gè)代碼會(huì)導(dǎo)致連接總是失敗,似乎很奇怪,后面發(fā)現(xiàn)原因是因?yàn)閍sync_connect的兩個(gè)參數(shù)失效了,但是寫(xiě)法和剛開(kāi)始的寫(xiě)法幾乎一樣,為啥后面這種寫(xiě)法會(huì)導(dǎo)致參數(shù)失效呢?

原因是co_await一個(gè)協(xié)程函數(shù)時(shí),其實(shí)做了兩件事:

  • 調(diào)用協(xié)程函數(shù)創(chuàng)建協(xié)程,這個(gè)步驟會(huì)創(chuàng)建協(xié)程幀,把參數(shù)和局部變量拷貝到協(xié)程幀里;

  • co_await執(zhí)行協(xié)程函數(shù);

回過(guò)頭來(lái)看auto lazy = async_connect("localhost", "8000"); 這個(gè)代碼調(diào)用協(xié)程函數(shù)創(chuàng)建了協(xié)程,這時(shí)候拷貝到協(xié)程幀里面的是兩個(gè)臨時(shí)變量,在這一行結(jié)束的時(shí)候臨時(shí)變量就析構(gòu)了,在下一行去co_await執(zhí)行這個(gè)協(xié)程的時(shí)候就會(huì)出現(xiàn)參數(shù)失效的問(wèn)題了。

co_await async_connect("localhost", "8000"); 這樣為什么沒(méi)問(wèn)題呢,因?yàn)閰f(xié)程創(chuàng)建和協(xié)程調(diào)用都在一行完成的,臨時(shí)變量知道協(xié)程執(zhí)行之后才會(huì)失效,因此不會(huì)有問(wèn)題。

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

審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 變量
    +關(guān)注

    關(guān)注

    0

    文章

    613

    瀏覽量

    28408
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    505

    瀏覽量

    19705

原文標(biāo)題:C++ 使用協(xié)程需要注意的問(wèn)題

文章出處:【微信號(hào):程序喵大人,微信公眾號(hào):程序喵大人】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    RAKsmart服務(wù)器升級(jí)需要注意哪些細(xì)節(jié)

    RAKsmart是一家知名的IDC(互聯(lián)網(wǎng)數(shù)據(jù)中心)服務(wù)提供商,為廣大用戶提供包括服務(wù)器托管、租用在內(nèi)的多種服務(wù)。當(dāng)您的業(yè)務(wù)需求發(fā)生變化或者技術(shù)進(jìn)步導(dǎo)致現(xiàn)有配置不再滿足要求時(shí),對(duì)服務(wù)器進(jìn)行升級(jí)就顯得尤為重要。以下是進(jìn)行RAKsmart服務(wù)器升級(jí)時(shí)需要注意的一些關(guān)鍵細(xì)節(jié)
    的頭像 發(fā)表于 09-25 09:56 ?203次閱讀

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

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

    bnc公頭注塑需要注意什么

    德索工程師說(shuō)道在BNC公頭注塑過(guò)程中,需要注意多個(gè)方面以確保產(chǎn)品的質(zhì)量和生產(chǎn)效率。以下是對(duì)這一過(guò)程中關(guān)鍵注意事項(xiàng)的詳細(xì)闡述:   材料選擇:根據(jù)BNC公頭的使用環(huán)境和性能要求,選擇合適的注塑
    的頭像 發(fā)表于 08-22 08:53 ?260次閱讀
    bnc公頭注塑<b class='flag-5'>需要注意</b>什么

    共模電感選型參數(shù)需要注意哪些

    電子發(fā)燒友網(wǎng)站提供《共模電感選型參數(shù)需要注意哪些.docx》資料免費(fèi)下載
    發(fā)表于 07-30 14:23 ?0次下載

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

    現(xiàn)場(chǎng)有多個(gè)AP,用相同的SSID,沒(méi)有使用AC,現(xiàn)場(chǎng)IR615S WiFi橋接AP WiFi時(shí),當(dāng)連接的AP關(guān)閉后,不能切換到到其他AP上,需要注意哪些設(shè)置?
    發(fā)表于 07-25 06:38

    FPGA實(shí)現(xiàn)SDIO訪問(wèn)需要注意的問(wèn)題

    FPGA實(shí)現(xiàn)SDIO訪問(wèn)時(shí),需要注意以下幾個(gè)關(guān)鍵問(wèn)題和細(xì)節(jié): 初始化過(guò)程: SDIO總線的初始化是確保FPGA與SD卡能夠正常通信的第一步。這包括設(shè)置時(shí)鐘頻率、配置數(shù)據(jù)傳輸模式以及校驗(yàn)協(xié)議等
    發(fā)表于 06-27 08:38

    應(yīng)用PLC需要注意哪些問(wèn)題

    PLC(可編程邏輯控制器)作為現(xiàn)代工業(yè)控制的核心設(shè)備,其應(yīng)用的廣泛性和重要性不言而喻。然而,在應(yīng)用PLC的過(guò)程中,也需要注意一系列問(wèn)題,以確保PLC系統(tǒng)的穩(wěn)定運(yùn)行和高效控制。本文將結(jié)合實(shí)際應(yīng)用經(jīng)驗(yàn),詳細(xì)探討應(yīng)用PLC時(shí)需要注意的問(wèn)題,并給出相應(yīng)的解決策略和建議。
    的頭像 發(fā)表于 06-17 11:29 ?598次閱讀

    FPGA的sata接口設(shè)計(jì)時(shí)需要注意哪些問(wèn)題

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

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

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

    鴻蒙原生應(yīng)用開(kāi)發(fā)-ArkTS語(yǔ)言基礎(chǔ)類庫(kù)異步并發(fā)簡(jiǎn)述async/await

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

    激光焊接技術(shù)在焊接鋁合金時(shí)需要注意什么

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

    智能手環(huán)設(shè)計(jì)需要注意哪些

    隨著電子技術(shù)的高速發(fā)展,可穿戴設(shè)備逐漸火爆,其中之一是智能手環(huán),作為現(xiàn)代可穿戴技術(shù)的熱門產(chǎn)品之一,它集成了多種功能,如健康檢測(cè)、運(yùn)動(dòng)跟蹤、通知提醒等,為了實(shí)現(xiàn)這些功能,需要用上哪些電路模塊,在設(shè)計(jì)時(shí)需要注意哪些?下面一起來(lái)看看吧
    的頭像 發(fā)表于 02-25 09:34 ?984次閱讀

    讓激光位移傳感器更精準(zhǔn),安裝的時(shí)候需要注意這些細(xì)節(jié)

    和應(yīng)用上也擁有豐富的經(jīng)驗(yàn)。本期小明就來(lái)盤點(diǎn)一下,激光位移傳感器在安裝的時(shí)候根據(jù)被測(cè)物及環(huán)境需要注意的關(guān)鍵點(diǎn)。↑更多明治精密激光位移傳感器資料點(diǎn)擊圖片獲取1材料/顏色存在
    的頭像 發(fā)表于 02-19 12:48 ?1208次閱讀
    讓激光位移傳感器更精準(zhǔn),安裝的時(shí)候<b class='flag-5'>需要注意</b><b class='flag-5'>這些</b><b class='flag-5'>細(xì)節(jié)</b>

    使用電容降壓時(shí)都需要注意哪些?

    使用電容降壓時(shí)都需要注意哪些? 電容降壓是一種常見(jiàn)且廣泛應(yīng)用的電路降壓方式,它可以將高電壓降低至設(shè)定的較低電壓,并且具有穩(wěn)定、簡(jiǎn)便、高效、可靠等優(yōu)點(diǎn)。然而,在使用電容降壓時(shí),我們需要注意一些關(guān)鍵
    的頭像 發(fā)表于 02-02 15:27 ?604次閱讀

    談?wù)?b class='flag-5'>協(xié)的那些事兒

    隨著異步編程的發(fā)展以及各種并發(fā)框架的普及,協(xié)作為一種異步編程規(guī)范在各類語(yǔ)言中地位逐步提高。我們不單單會(huì)在自己的程序中使用協(xié),各類框架如fastapi,aiohttp等也都是基于異步
    的頭像 發(fā)表于 01-26 11:36 ?1124次閱讀
    談?wù)?b class='flag-5'>協(xié)</b><b class='flag-5'>程</b>的那些事兒
    主站蜘蛛池模板: 2017天天拍天天拍香蕉视频| 欧美人妇无码精品久久| 久久这里有精品| 乳色吐息在线观看全集免费观看| 亚洲精品久久无码AV片WWW| japanese from色系| 好色美女小雅| 日本免费xxx| 嘴巴舔着她的私处插| 国产精品无码视频一区二区| 暖暖 视频 免费 高清 在线观看| 亚洲视频中文字幕在线| 动漫美女被吸奶| 久久视频这里只精品99re8久| 婷婷五月久久丁香国产综合| 99久久综合| 九九精品视频一区二区三区| 沈芯语麻豆0076 视频| 99久久国产露脸精品竹菊传煤| 精品AV国产一区二区三区| 色欲人妻无码AV专区| 99久女女精品视频在线观看| 久久66热在线视频精品| 小寡妇好紧进去了好大看视频| Y8848高清私人影院软件优势| 久热这里在线精品| 亚洲精品乱码电影在线观看| 国产a在线不卡| 欧美亚洲日韩一道免费观看| 在线亚洲中文精品第1页| 国内国外精品影片无人区| 神马电影我不卡4k手机在线观看| av天堂电影网| 麻豆一区二区免费播放网站| 亚洲伊人情人综合网站| 国产午夜精品美女免费大片| 色AV色婷婷66人妻久久久| FREEHDXXXX学生妹| 免费一区在线观看| 综合久久伊人| 久久这里只精品热在线18|