chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(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é)程,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ù)失效了,但是寫法和剛開(kāi)始的寫法幾乎一樣,為啥后面這種寫法會(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)容及配圖由入駐作者撰寫或者入駐合作網(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

    文章

    615

    瀏覽量

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

    關(guān)注

    0

    文章

    508

    瀏覽量

    20653

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

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

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    用戶在使用GPIO反跳功能時(shí)需要注意哪些限制?

    用戶在使用GPIO反跳功能時(shí)需要注意哪些限制?
    發(fā)表于 08-26 06:32

    振弦式土體沉降計(jì)鉆孔埋設(shè)需要注意什么?

    、確保長(zhǎng)期監(jiān)測(cè)穩(wěn)定性的前提。振弦式土體沉降計(jì)鉆孔埋設(shè)需要注意什么?關(guān)鍵注意事項(xiàng)規(guī)避施工風(fēng)險(xiǎn)工程實(shí)踐中需重點(diǎn)管控四類風(fēng)險(xiǎn):鉆孔質(zhì)量控制:傾斜度偏差需≤2°,防止儀器偏斜
    的頭像 發(fā)表于 08-19 13:56 ?401次閱讀
    振弦式土體沉降計(jì)鉆孔埋設(shè)<b class='flag-5'>需要注意</b>什么?

    企業(yè)選擇SDWAN方案時(shí),需要注意哪些?

    ##企業(yè)選擇SDWAN方案時(shí),需要注意哪些?在數(shù)字化轉(zhuǎn)型浪潮中,企業(yè)廣域網(wǎng)正經(jīng)歷從“連通即可”向“智能、安全、云原生”的深刻變革。SD-WAN技術(shù)憑借其顛覆性的架構(gòu)理念,成為企業(yè)優(yōu)化網(wǎng)絡(luò)性能
    的頭像 發(fā)表于 08-15 10:03 ?1109次閱讀
    企業(yè)選擇SDWAN方案時(shí),<b class='flag-5'>需要注意</b>哪些?

    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ā)表于 08-06 07:39

    請(qǐng)問(wèn)工程移植都有哪些需要注意的地方?

    ST的固件庫(kù)還是挺豐富的,有時(shí)候我們直接移植工程還是挺方便的,不過(guò)總是會(huì)有各種各樣的報(bào)錯(cuò)存在,在移植的時(shí)候有哪些需要注意的嗎?或者一些常見(jiàn)的報(bào)錯(cuò)如何解決?
    發(fā)表于 07-11 06:50

    使用STM32CubeMX進(jìn)行配置USB的時(shí)候,有哪些小的需要注意細(xì)節(jié)?

    在使用STM32CubeMX進(jìn)行配置USB的時(shí)候,是參照例程進(jìn)行的配置,自己配置的就是沒(méi)有成功,例程就滅有問(wèn)題,總感覺(jué)哪里沒(méi)有打開(kāi)?有人遇到過(guò)需要注意的小細(xì)節(jié)嗎?
    發(fā)表于 04-23 06:54

    LuatOS協(xié)深度解析:小白也能10分鐘學(xué)會(huì),代碼效率直接起飛!

    嵌入式開(kāi)發(fā)如何兼顧效率與簡(jiǎn)潔?LuatOS協(xié)給出完美答案!它用類線程的語(yǔ)法封裝異步邏輯,讓多任務(wù)開(kāi)發(fā)像單線程一樣簡(jiǎn)單。本文用圖文并茂的方式拆解協(xié)
    的頭像 發(fā)表于 04-10 15:23 ?376次閱讀
    LuatOS<b class='flag-5'>協(xié)</b><b class='flag-5'>程</b>深度解析:小白也能10分鐘學(xué)會(huì),代碼效率直接起飛!

    10分鐘上手寫代碼,LuatOS協(xié)輕松掌握!

    10分鐘學(xué)會(huì)LuatOS協(xié),從此你的程序也能像通勤族利用碎片時(shí)間一樣游刃有余?,F(xiàn)在就去動(dòng)手試一試,開(kāi)啟異步編程新體驗(yàn)! 寫給第一次聽(tīng)說(shuō)協(xié)的你?: 別怕!
    的頭像 發(fā)表于 04-10 15:18 ?395次閱讀
    10分鐘上手寫代碼,LuatOS<b class='flag-5'>協(xié)</b><b class='flag-5'>程</b>輕松掌握!

    穩(wěn)壓器在安裝接線前需要注意哪些

    穩(wěn)壓器是一種非常重要的電氣設(shè)備,它可以有效地解決電壓不穩(wěn)定、波動(dòng)過(guò)大等問(wèn)題,保證設(shè)備的正常運(yùn)行,然而,穩(wěn)壓器接線并非簡(jiǎn)單地將線接好就行,而是需要注意一些事項(xiàng),以確保其能夠安全、有效地發(fā)揮應(yīng)有的作用,下面小編來(lái)說(shuō)說(shuō)穩(wěn)壓器在安裝接線前需要注意哪些。
    的頭像 發(fā)表于 04-03 15:20 ?473次閱讀
    穩(wěn)壓器在安裝接線前<b class='flag-5'>需要注意</b>哪些

    進(jìn)程、線程、協(xié)傻傻分不清?一文帶你徹底扒光它們的\"底褲\"!

    權(quán)(yield)實(shí)現(xiàn)協(xié)作,單線程內(nèi)玩出多任務(wù)的感覺(jué)。 技術(shù)細(xì)節(jié)協(xié)切換成本≈打哈欠(0.1μs~1μs) 阻塞操作會(huì)直接讓出CPU(比如
    發(fā)表于 03-26 09:27

    變頻器控制回路布線需要注意什么

    變頻器控制回路布線時(shí)需要注意的幾個(gè)方面,以確保布線的專業(yè)性和穩(wěn)定性。 一、避免干擾:主電路與控制回路分離 變頻器的主電路(動(dòng)力線)通常包含高電壓、大電流,因此會(huì)產(chǎn)生較強(qiáng)的電磁場(chǎng),這些電磁場(chǎng)可能干擾控制回路的
    的頭像 發(fā)表于 03-11 15:33 ?723次閱讀
    變頻器控制回路布線<b class='flag-5'>需要注意</b>什么

    速度探頭在使用過(guò)程中需要注意哪些問(wèn)題呢

    速度探頭在使用過(guò)程中需要注意安裝與維護(hù)、參數(shù)設(shè)置與校準(zhǔn)、使用注意事項(xiàng)以及安全注意事項(xiàng)等多個(gè)方面。只有做好這些工作,才能確保探頭的正常工作、測(cè)量精度和安全性。
    的頭像 發(fā)表于 02-06 15:11 ?673次閱讀

    ADS1247想配置為單端輸入,都需要注意哪些寄存器?

    這些開(kāi)關(guān)是由哪些寄存器控制的,我在手冊(cè)里怎么沒(méi)有找到,我想配置為單端輸入,不知道都需要注意哪些寄存器,在線等答案,望各位大俠幫忙
    發(fā)表于 01-15 08:31

    測(cè)試光伏逆變器需要注意哪些地方呢?

    在進(jìn)行光伏逆變器測(cè)試時(shí),需要注意以下幾個(gè)關(guān)鍵方面:1.電氣安全測(cè)試:包括輸入端口絕緣電阻測(cè)試、漏電測(cè)試、接地連接測(cè)試等,以確保逆變器在電氣方面的安全性。2.性能參數(shù)測(cè)試:測(cè)試包括額定功率、極大
    的頭像 發(fā)表于 11-13 17:17 ?1217次閱讀
    測(cè)試光伏逆變器<b class='flag-5'>需要注意</b>哪些地方呢?

    位置開(kāi)關(guān)與接近開(kāi)關(guān)IB50-P80T-D2-GY531需要注意哪些問(wèn)題

    位置開(kāi)關(guān)與接近開(kāi)關(guān)在應(yīng)用中需要注意的問(wèn)題涉及多個(gè)方面,包括安裝、使用、維護(hù)以及環(huán)境適應(yīng)性等。為了確保開(kāi)關(guān)的正常工作和延長(zhǎng)使用壽命,必須嚴(yán)格遵守相關(guān)規(guī)定和操作規(guī)程。
    的頭像 發(fā)表于 11-07 11:12 ?845次閱讀